diff options
Diffstat (limited to 'tools')
120 files changed, 5566 insertions, 1402 deletions
diff --git a/tools/Makefile b/tools/Makefile index 6bf68fe7dd29..f10b64d8c674 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -16,6 +16,7 @@ help: | |||
16 | @echo ' gpio - GPIO tools' | 16 | @echo ' gpio - GPIO tools' |
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 ' lguest - a minimal 32-bit x86 hypervisor' | 20 | @echo ' lguest - a minimal 32-bit x86 hypervisor' |
20 | @echo ' net - misc networking tools' | 21 | @echo ' net - misc networking tools' |
21 | @echo ' perf - Linux performance measurement and analysis tool' | 22 | @echo ' perf - Linux performance measurement and analysis tool' |
@@ -110,10 +111,13 @@ tmon_install: | |||
110 | freefall_install: | 111 | freefall_install: |
111 | $(call descend,laptop/$(@:_install=),install) | 112 | $(call descend,laptop/$(@:_install=),install) |
112 | 113 | ||
114 | kvm_stat_install: | ||
115 | $(call descend,kvm/$(@:_install=),install) | ||
116 | |||
113 | install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ | 117 | install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ |
114 | perf_install selftests_install turbostat_install usb_install \ | 118 | perf_install selftests_install turbostat_install usb_install \ |
115 | virtio_install vm_install net_install x86_energy_perf_policy_install \ | 119 | virtio_install vm_install net_install x86_energy_perf_policy_install \ |
116 | tmon_install freefall_install objtool_install | 120 | tmon_install freefall_install objtool_install kvm_stat_install |
117 | 121 | ||
118 | acpi_clean: | 122 | acpi_clean: |
119 | $(call descend,power/acpi,clean) | 123 | $(call descend,power/acpi,clean) |
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index ee566e8bd1cf..27f3583193e6 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build | |||
@@ -58,8 +58,8 @@ quiet_cmd_mkdir = MKDIR $(dir $@) | |||
58 | quiet_cmd_cc_o_c = CC $@ | 58 | quiet_cmd_cc_o_c = CC $@ |
59 | cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< | 59 | cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< |
60 | 60 | ||
61 | quiet_cmd_cc_i_c = CPP $@ | 61 | quiet_cmd_cpp_i_c = CPP $@ |
62 | cmd_cc_i_c = $(CC) $(c_flags) -E -o $@ $< | 62 | cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $< |
63 | 63 | ||
64 | quiet_cmd_cc_s_c = AS $@ | 64 | quiet_cmd_cc_s_c = AS $@ |
65 | cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< | 65 | cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< |
@@ -83,11 +83,11 @@ $(OUTPUT)%.o: %.S FORCE | |||
83 | 83 | ||
84 | $(OUTPUT)%.i: %.c FORCE | 84 | $(OUTPUT)%.i: %.c FORCE |
85 | $(call rule_mkdir) | 85 | $(call rule_mkdir) |
86 | $(call if_changed_dep,cc_i_c) | 86 | $(call if_changed_dep,cpp_i_c) |
87 | 87 | ||
88 | $(OUTPUT)%.s: %.S FORCE | 88 | $(OUTPUT)%.s: %.S FORCE |
89 | $(call rule_mkdir) | 89 | $(call rule_mkdir) |
90 | $(call if_changed_dep,cc_i_c) | 90 | $(call if_changed_dep,cpp_i_c) |
91 | 91 | ||
92 | $(OUTPUT)%.s: %.c FORCE | 92 | $(OUTPUT)%.s: %.c FORCE |
93 | $(call rule_mkdir) | 93 | $(call rule_mkdir) |
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 4d198d5c4203..c155d6bc47a7 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | CC = $(CROSS_COMPILE)gcc | 1 | CC = $(CROSS_COMPILE)gcc |
2 | CFLAGS += -Wall -g -D_GNU_SOURCE | 2 | CFLAGS += -O2 -Wall -g -D_GNU_SOURCE |
3 | 3 | ||
4 | all: lsgpio | 4 | all: lsgpio |
5 | 5 | ||
diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c index 1124da375942..eb3f56efd215 100644 --- a/tools/gpio/lsgpio.c +++ b/tools/gpio/lsgpio.c | |||
@@ -147,7 +147,7 @@ void print_usage(void) | |||
147 | 147 | ||
148 | int main(int argc, char **argv) | 148 | int main(int argc, char **argv) |
149 | { | 149 | { |
150 | const char *device_name; | 150 | const char *device_name = NULL; |
151 | int ret; | 151 | int ret; |
152 | int c; | 152 | int c; |
153 | 153 | ||
diff --git a/tools/hv/lsvmbus b/tools/hv/lsvmbus index 162a3784d80e..e8fecd61871f 100644 --- a/tools/hv/lsvmbus +++ b/tools/hv/lsvmbus | |||
@@ -35,6 +35,7 @@ vmbus_dev_dict = { | |||
35 | '{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}' : 'Synthetic SCSI Controller', | 35 | '{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}' : 'Synthetic SCSI Controller', |
36 | '{2f9bcc4a-0069-4af3-b76b-6fd0be528cda}' : 'Synthetic fiber channel adapter', | 36 | '{2f9bcc4a-0069-4af3-b76b-6fd0be528cda}' : 'Synthetic fiber channel adapter', |
37 | '{8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}' : 'Synthetic RDMA adapter', | 37 | '{8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501}' : 'Synthetic RDMA adapter', |
38 | '{44c4f61d-4444-4400-9d52-802e27ede19f}' : 'PCI Express pass-through', | ||
38 | '{276aacf4-ac15-426c-98dd-7521ad3f01fe}' : '[Reserved system device]', | 39 | '{276aacf4-ac15-426c-98dd-7521ad3f01fe}' : '[Reserved system device]', |
39 | '{f8e65716-3cb3-4a06-9a60-1889c5cccab5}' : '[Reserved system device]', | 40 | '{f8e65716-3cb3-4a06-9a60-1889c5cccab5}' : '[Reserved system device]', |
40 | '{3375baf4-9e15-4b30-b765-67acb10d607b}' : '[Reserved system device]', | 41 | '{3375baf4-9e15-4b30-b765-67acb10d607b}' : '[Reserved system device]', |
diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c index 01c4f67801e0..2429c78de940 100644 --- a/tools/iio/generic_buffer.c +++ b/tools/iio/generic_buffer.c | |||
@@ -35,6 +35,15 @@ | |||
35 | #include "iio_utils.h" | 35 | #include "iio_utils.h" |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * enum autochan - state for the automatic channel enabling mechanism | ||
39 | */ | ||
40 | enum autochan { | ||
41 | AUTOCHANNELS_DISABLED, | ||
42 | AUTOCHANNELS_ENABLED, | ||
43 | AUTOCHANNELS_ACTIVE, | ||
44 | }; | ||
45 | |||
46 | /** | ||
38 | * size_from_channelarray() - calculate the storage size of a scan | 47 | * size_from_channelarray() - calculate the storage size of a scan |
39 | * @channels: the channel info array | 48 | * @channels: the channel info array |
40 | * @num_channels: number of channels | 49 | * @num_channels: number of channels |
@@ -191,10 +200,51 @@ void process_scan(char *data, | |||
191 | printf("\n"); | 200 | printf("\n"); |
192 | } | 201 | } |
193 | 202 | ||
203 | static int enable_disable_all_channels(char *dev_dir_name, int enable) | ||
204 | { | ||
205 | const struct dirent *ent; | ||
206 | char scanelemdir[256]; | ||
207 | DIR *dp; | ||
208 | int ret; | ||
209 | |||
210 | snprintf(scanelemdir, sizeof(scanelemdir), | ||
211 | FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); | ||
212 | scanelemdir[sizeof(scanelemdir)-1] = '\0'; | ||
213 | |||
214 | dp = opendir(scanelemdir); | ||
215 | if (!dp) { | ||
216 | fprintf(stderr, "Enabling/disabling channels: can't open %s\n", | ||
217 | scanelemdir); | ||
218 | return -EIO; | ||
219 | } | ||
220 | |||
221 | ret = -ENOENT; | ||
222 | while (ent = readdir(dp), ent) { | ||
223 | if (iioutils_check_suffix(ent->d_name, "_en")) { | ||
224 | printf("%sabling: %s\n", | ||
225 | enable ? "En" : "Dis", | ||
226 | ent->d_name); | ||
227 | ret = write_sysfs_int(ent->d_name, scanelemdir, | ||
228 | enable); | ||
229 | if (ret < 0) | ||
230 | fprintf(stderr, "Failed to enable/disable %s\n", | ||
231 | ent->d_name); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (closedir(dp) == -1) { | ||
236 | perror("Enabling/disabling channels: " | ||
237 | "Failed to close directory"); | ||
238 | return -errno; | ||
239 | } | ||
240 | return 0; | ||
241 | } | ||
242 | |||
194 | void print_usage(void) | 243 | void print_usage(void) |
195 | { | 244 | { |
196 | fprintf(stderr, "Usage: generic_buffer [options]...\n" | 245 | fprintf(stderr, "Usage: generic_buffer [options]...\n" |
197 | "Capture, convert and output data from IIO device buffer\n" | 246 | "Capture, convert and output data from IIO device buffer\n" |
247 | " -a Auto-activate all available channels\n" | ||
198 | " -c <n> Do n conversions\n" | 248 | " -c <n> Do n conversions\n" |
199 | " -e Disable wait for event (new data)\n" | 249 | " -e Disable wait for event (new data)\n" |
200 | " -g Use trigger-less mode\n" | 250 | " -g Use trigger-less mode\n" |
@@ -225,12 +275,16 @@ int main(int argc, char **argv) | |||
225 | int scan_size; | 275 | int scan_size; |
226 | int noevents = 0; | 276 | int noevents = 0; |
227 | int notrigger = 0; | 277 | int notrigger = 0; |
278 | enum autochan autochannels = AUTOCHANNELS_DISABLED; | ||
228 | char *dummy; | 279 | char *dummy; |
229 | 280 | ||
230 | struct iio_channel_info *channels; | 281 | struct iio_channel_info *channels; |
231 | 282 | ||
232 | while ((c = getopt(argc, argv, "c:egl:n:t:w:")) != -1) { | 283 | while ((c = getopt(argc, argv, "ac:egl:n:t:w:")) != -1) { |
233 | switch (c) { | 284 | switch (c) { |
285 | case 'a': | ||
286 | autochannels = AUTOCHANNELS_ENABLED; | ||
287 | break; | ||
234 | case 'c': | 288 | case 'c': |
235 | errno = 0; | 289 | errno = 0; |
236 | num_loops = strtoul(optarg, &dummy, 10); | 290 | num_loops = strtoul(optarg, &dummy, 10); |
@@ -304,7 +358,19 @@ int main(int argc, char **argv) | |||
304 | } | 358 | } |
305 | } | 359 | } |
306 | 360 | ||
307 | /* Verify the trigger exists */ | 361 | /* Look for this "-devN" trigger */ |
362 | trig_num = find_type_by_name(trigger_name, "trigger"); | ||
363 | if (trig_num < 0) { | ||
364 | /* OK try the simpler "-trigger" suffix instead */ | ||
365 | free(trigger_name); | ||
366 | ret = asprintf(&trigger_name, | ||
367 | "%s-trigger", device_name); | ||
368 | if (ret < 0) { | ||
369 | ret = -ENOMEM; | ||
370 | goto error_free_dev_dir_name; | ||
371 | } | ||
372 | } | ||
373 | |||
308 | trig_num = find_type_by_name(trigger_name, "trigger"); | 374 | trig_num = find_type_by_name(trigger_name, "trigger"); |
309 | if (trig_num < 0) { | 375 | if (trig_num < 0) { |
310 | fprintf(stderr, "Failed to find the trigger %s\n", | 376 | fprintf(stderr, "Failed to find the trigger %s\n", |
@@ -328,12 +394,47 @@ int main(int argc, char **argv) | |||
328 | "diag %s\n", dev_dir_name); | 394 | "diag %s\n", dev_dir_name); |
329 | goto error_free_triggername; | 395 | goto error_free_triggername; |
330 | } | 396 | } |
331 | if (!num_channels) { | 397 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { |
398 | fprintf(stderr, "Auto-channels selected but some channels " | ||
399 | "are already activated in sysfs\n"); | ||
400 | fprintf(stderr, "Proceeding without activating any channels\n"); | ||
401 | } | ||
402 | |||
403 | if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) { | ||
404 | fprintf(stderr, | ||
405 | "No channels are enabled, enabling all channels\n"); | ||
406 | |||
407 | ret = enable_disable_all_channels(dev_dir_name, 1); | ||
408 | if (ret) { | ||
409 | fprintf(stderr, "Failed to enable all channels\n"); | ||
410 | goto error_free_triggername; | ||
411 | } | ||
412 | |||
413 | /* This flags that we need to disable the channels again */ | ||
414 | autochannels = AUTOCHANNELS_ACTIVE; | ||
415 | |||
416 | ret = build_channel_array(dev_dir_name, &channels, | ||
417 | &num_channels); | ||
418 | if (ret) { | ||
419 | fprintf(stderr, "Problem reading scan element " | ||
420 | "information\n" | ||
421 | "diag %s\n", dev_dir_name); | ||
422 | goto error_disable_channels; | ||
423 | } | ||
424 | if (!num_channels) { | ||
425 | fprintf(stderr, "Still no channels after " | ||
426 | "auto-enabling, giving up\n"); | ||
427 | goto error_disable_channels; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { | ||
332 | fprintf(stderr, | 432 | fprintf(stderr, |
333 | "No channels are enabled, we have nothing to scan.\n"); | 433 | "No channels are enabled, we have nothing to scan.\n"); |
334 | fprintf(stderr, "Enable channels manually in " | 434 | fprintf(stderr, "Enable channels manually in " |
335 | FORMAT_SCAN_ELEMENTS_DIR | 435 | FORMAT_SCAN_ELEMENTS_DIR |
336 | "/*_en and try again.\n", dev_dir_name); | 436 | "/*_en or pass -a to autoenable channels and " |
437 | "try again.\n", dev_dir_name); | ||
337 | ret = -ENOENT; | 438 | ret = -ENOENT; |
338 | goto error_free_triggername; | 439 | goto error_free_triggername; |
339 | } | 440 | } |
@@ -467,7 +568,12 @@ error_free_channels: | |||
467 | error_free_triggername: | 568 | error_free_triggername: |
468 | if (datardytrigger) | 569 | if (datardytrigger) |
469 | free(trigger_name); | 570 | free(trigger_name); |
470 | 571 | error_disable_channels: | |
572 | if (autochannels == AUTOCHANNELS_ACTIVE) { | ||
573 | ret = enable_disable_all_channels(dev_dir_name, 0); | ||
574 | if (ret) | ||
575 | fprintf(stderr, "Failed to disable all channels\n"); | ||
576 | } | ||
471 | error_free_dev_dir_name: | 577 | error_free_dev_dir_name: |
472 | free(dev_dir_name); | 578 | free(dev_dir_name); |
473 | 579 | ||
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index d51eb04202e9..d9b7e0f306c6 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c | |||
@@ -53,6 +53,10 @@ static const char * const iio_chan_type_name_spec[] = { | |||
53 | [IIO_ENERGY] = "energy", | 53 | [IIO_ENERGY] = "energy", |
54 | [IIO_DISTANCE] = "distance", | 54 | [IIO_DISTANCE] = "distance", |
55 | [IIO_VELOCITY] = "velocity", | 55 | [IIO_VELOCITY] = "velocity", |
56 | [IIO_CONCENTRATION] = "concentration", | ||
57 | [IIO_RESISTANCE] = "resistance", | ||
58 | [IIO_PH] = "ph", | ||
59 | [IIO_UVINDEX] = "uvindex", | ||
56 | }; | 60 | }; |
57 | 61 | ||
58 | static const char * const iio_ev_type_text[] = { | 62 | static const char * const iio_ev_type_text[] = { |
@@ -90,6 +94,7 @@ static const char * const iio_modifier_names[] = { | |||
90 | [IIO_MOD_LIGHT_RED] = "red", | 94 | [IIO_MOD_LIGHT_RED] = "red", |
91 | [IIO_MOD_LIGHT_GREEN] = "green", | 95 | [IIO_MOD_LIGHT_GREEN] = "green", |
92 | [IIO_MOD_LIGHT_BLUE] = "blue", | 96 | [IIO_MOD_LIGHT_BLUE] = "blue", |
97 | [IIO_MOD_LIGHT_UV] = "uv", | ||
93 | [IIO_MOD_QUATERNION] = "quaternion", | 98 | [IIO_MOD_QUATERNION] = "quaternion", |
94 | [IIO_MOD_TEMP_AMBIENT] = "ambient", | 99 | [IIO_MOD_TEMP_AMBIENT] = "ambient", |
95 | [IIO_MOD_TEMP_OBJECT] = "object", | 100 | [IIO_MOD_TEMP_OBJECT] = "object", |
@@ -102,6 +107,10 @@ static const char * const iio_modifier_names[] = { | |||
102 | [IIO_MOD_WALKING] = "walking", | 107 | [IIO_MOD_WALKING] = "walking", |
103 | [IIO_MOD_STILL] = "still", | 108 | [IIO_MOD_STILL] = "still", |
104 | [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", | 109 | [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", |
110 | [IIO_MOD_I] = "i", | ||
111 | [IIO_MOD_Q] = "q", | ||
112 | [IIO_MOD_CO2] = "co2", | ||
113 | [IIO_MOD_VOC] = "voc", | ||
105 | }; | 114 | }; |
106 | 115 | ||
107 | static bool event_is_known(struct iio_event_data *event) | 116 | static bool event_is_known(struct iio_event_data *event) |
@@ -136,6 +145,10 @@ static bool event_is_known(struct iio_event_data *event) | |||
136 | case IIO_ENERGY: | 145 | case IIO_ENERGY: |
137 | case IIO_DISTANCE: | 146 | case IIO_DISTANCE: |
138 | case IIO_VELOCITY: | 147 | case IIO_VELOCITY: |
148 | case IIO_CONCENTRATION: | ||
149 | case IIO_RESISTANCE: | ||
150 | case IIO_PH: | ||
151 | case IIO_UVINDEX: | ||
139 | break; | 152 | break; |
140 | default: | 153 | default: |
141 | return false; | 154 | return false; |
@@ -162,6 +175,7 @@ static bool event_is_known(struct iio_event_data *event) | |||
162 | case IIO_MOD_LIGHT_RED: | 175 | case IIO_MOD_LIGHT_RED: |
163 | case IIO_MOD_LIGHT_GREEN: | 176 | case IIO_MOD_LIGHT_GREEN: |
164 | case IIO_MOD_LIGHT_BLUE: | 177 | case IIO_MOD_LIGHT_BLUE: |
178 | case IIO_MOD_LIGHT_UV: | ||
165 | case IIO_MOD_QUATERNION: | 179 | case IIO_MOD_QUATERNION: |
166 | case IIO_MOD_TEMP_AMBIENT: | 180 | case IIO_MOD_TEMP_AMBIENT: |
167 | case IIO_MOD_TEMP_OBJECT: | 181 | case IIO_MOD_TEMP_OBJECT: |
@@ -174,6 +188,10 @@ static bool event_is_known(struct iio_event_data *event) | |||
174 | case IIO_MOD_WALKING: | 188 | case IIO_MOD_WALKING: |
175 | case IIO_MOD_STILL: | 189 | case IIO_MOD_STILL: |
176 | case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z: | 190 | case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z: |
191 | case IIO_MOD_I: | ||
192 | case IIO_MOD_Q: | ||
193 | case IIO_MOD_CO2: | ||
194 | case IIO_MOD_VOC: | ||
177 | break; | 195 | break; |
178 | default: | 196 | default: |
179 | return false; | 197 | return false; |
diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index e3503bfe538b..780f2014f8fa 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h | |||
@@ -52,6 +52,13 @@ struct iio_channel_info { | |||
52 | unsigned location; | 52 | unsigned location; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static inline int iioutils_check_suffix(const char *str, const char *suffix) | ||
56 | { | ||
57 | return strlen(str) >= strlen(suffix) && | ||
58 | strncmp(str+strlen(str)-strlen(suffix), | ||
59 | suffix, strlen(suffix)) == 0; | ||
60 | } | ||
61 | |||
55 | int iioutils_break_up_name(const char *full_name, char **generic_name); | 62 | int iioutils_break_up_name(const char *full_name, char **generic_name); |
56 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, | 63 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, |
57 | unsigned *shift, uint64_t *mask, unsigned *be, | 64 | unsigned *shift, uint64_t *mask, unsigned *be, |
diff --git a/tools/kvm/kvm_stat/Makefile b/tools/kvm/kvm_stat/Makefile new file mode 100644 index 000000000000..5b1cba57e3b3 --- /dev/null +++ b/tools/kvm/kvm_stat/Makefile | |||
@@ -0,0 +1,41 @@ | |||
1 | include ../../scripts/Makefile.include | ||
2 | include ../../scripts/utilities.mak | ||
3 | BINDIR=usr/bin | ||
4 | MANDIR=usr/share/man | ||
5 | MAN1DIR=$(MANDIR)/man1 | ||
6 | |||
7 | MAN1=kvm_stat.1 | ||
8 | |||
9 | A2X=a2x | ||
10 | a2x_path := $(call get-executable,$(A2X)) | ||
11 | |||
12 | all: man | ||
13 | |||
14 | ifneq ($(findstring $(MAKEFLAGS),s),s) | ||
15 | ifneq ($(V),1) | ||
16 | QUIET_A2X = @echo ' A2X '$@; | ||
17 | endif | ||
18 | endif | ||
19 | |||
20 | %.1: %.txt | ||
21 | ifeq ($(a2x_path),) | ||
22 | $(error "You need to install asciidoc for man pages") | ||
23 | else | ||
24 | $(QUIET_A2X)$(A2X) --doctype manpage --format manpage $< | ||
25 | endif | ||
26 | |||
27 | clean: | ||
28 | rm -f $(MAN1) | ||
29 | |||
30 | man: $(MAN1) | ||
31 | |||
32 | install-man: man | ||
33 | install -d -m 755 $(INSTALL_ROOT)/$(MAN1DIR) | ||
34 | install -m 644 kvm_stat.1 $(INSTALL_ROOT)/$(MAN1DIR) | ||
35 | |||
36 | install-tools: | ||
37 | install -d -m 755 $(INSTALL_ROOT)/$(BINDIR) | ||
38 | install -m 755 -p "kvm_stat" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" | ||
39 | |||
40 | install: install-tools install-man | ||
41 | .PHONY: all clean man install-tools install-man install | ||
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat new file mode 100755 index 000000000000..581278c58488 --- /dev/null +++ b/tools/kvm/kvm_stat/kvm_stat | |||
@@ -0,0 +1,1127 @@ | |||
1 | #!/usr/bin/python | ||
2 | # | ||
3 | # top-like utility for displaying kvm statistics | ||
4 | # | ||
5 | # Copyright 2006-2008 Qumranet Technologies | ||
6 | # Copyright 2008-2011 Red Hat, Inc. | ||
7 | # | ||
8 | # Authors: | ||
9 | # Avi Kivity <avi@redhat.com> | ||
10 | # | ||
11 | # This work is licensed under the terms of the GNU GPL, version 2. See | ||
12 | # the COPYING file in the top-level directory. | ||
13 | """The kvm_stat module outputs statistics about running KVM VMs | ||
14 | |||
15 | Three different ways of output formatting are available: | ||
16 | - as a top-like text ui | ||
17 | - in a key -> value format | ||
18 | - in an all keys, all values format | ||
19 | |||
20 | The data is sampled from the KVM's debugfs entries and its perf events. | ||
21 | """ | ||
22 | |||
23 | import curses | ||
24 | import sys | ||
25 | import os | ||
26 | import time | ||
27 | import optparse | ||
28 | import ctypes | ||
29 | import fcntl | ||
30 | import resource | ||
31 | import struct | ||
32 | import re | ||
33 | from collections import defaultdict | ||
34 | from time import sleep | ||
35 | |||
36 | VMX_EXIT_REASONS = { | ||
37 | 'EXCEPTION_NMI': 0, | ||
38 | 'EXTERNAL_INTERRUPT': 1, | ||
39 | 'TRIPLE_FAULT': 2, | ||
40 | 'PENDING_INTERRUPT': 7, | ||
41 | 'NMI_WINDOW': 8, | ||
42 | 'TASK_SWITCH': 9, | ||
43 | 'CPUID': 10, | ||
44 | 'HLT': 12, | ||
45 | 'INVLPG': 14, | ||
46 | 'RDPMC': 15, | ||
47 | 'RDTSC': 16, | ||
48 | 'VMCALL': 18, | ||
49 | 'VMCLEAR': 19, | ||
50 | 'VMLAUNCH': 20, | ||
51 | 'VMPTRLD': 21, | ||
52 | 'VMPTRST': 22, | ||
53 | 'VMREAD': 23, | ||
54 | 'VMRESUME': 24, | ||
55 | 'VMWRITE': 25, | ||
56 | 'VMOFF': 26, | ||
57 | 'VMON': 27, | ||
58 | 'CR_ACCESS': 28, | ||
59 | 'DR_ACCESS': 29, | ||
60 | 'IO_INSTRUCTION': 30, | ||
61 | 'MSR_READ': 31, | ||
62 | 'MSR_WRITE': 32, | ||
63 | 'INVALID_STATE': 33, | ||
64 | 'MWAIT_INSTRUCTION': 36, | ||
65 | 'MONITOR_INSTRUCTION': 39, | ||
66 | 'PAUSE_INSTRUCTION': 40, | ||
67 | 'MCE_DURING_VMENTRY': 41, | ||
68 | 'TPR_BELOW_THRESHOLD': 43, | ||
69 | 'APIC_ACCESS': 44, | ||
70 | 'EPT_VIOLATION': 48, | ||
71 | 'EPT_MISCONFIG': 49, | ||
72 | 'WBINVD': 54, | ||
73 | 'XSETBV': 55, | ||
74 | 'APIC_WRITE': 56, | ||
75 | 'INVPCID': 58, | ||
76 | } | ||
77 | |||
78 | SVM_EXIT_REASONS = { | ||
79 | 'READ_CR0': 0x000, | ||
80 | 'READ_CR3': 0x003, | ||
81 | 'READ_CR4': 0x004, | ||
82 | 'READ_CR8': 0x008, | ||
83 | 'WRITE_CR0': 0x010, | ||
84 | 'WRITE_CR3': 0x013, | ||
85 | 'WRITE_CR4': 0x014, | ||
86 | 'WRITE_CR8': 0x018, | ||
87 | 'READ_DR0': 0x020, | ||
88 | 'READ_DR1': 0x021, | ||
89 | 'READ_DR2': 0x022, | ||
90 | 'READ_DR3': 0x023, | ||
91 | 'READ_DR4': 0x024, | ||
92 | 'READ_DR5': 0x025, | ||
93 | 'READ_DR6': 0x026, | ||
94 | 'READ_DR7': 0x027, | ||
95 | 'WRITE_DR0': 0x030, | ||
96 | 'WRITE_DR1': 0x031, | ||
97 | 'WRITE_DR2': 0x032, | ||
98 | 'WRITE_DR3': 0x033, | ||
99 | 'WRITE_DR4': 0x034, | ||
100 | 'WRITE_DR5': 0x035, | ||
101 | 'WRITE_DR6': 0x036, | ||
102 | 'WRITE_DR7': 0x037, | ||
103 | 'EXCP_BASE': 0x040, | ||
104 | 'INTR': 0x060, | ||
105 | 'NMI': 0x061, | ||
106 | 'SMI': 0x062, | ||
107 | 'INIT': 0x063, | ||
108 | 'VINTR': 0x064, | ||
109 | 'CR0_SEL_WRITE': 0x065, | ||
110 | 'IDTR_READ': 0x066, | ||
111 | 'GDTR_READ': 0x067, | ||
112 | 'LDTR_READ': 0x068, | ||
113 | 'TR_READ': 0x069, | ||
114 | 'IDTR_WRITE': 0x06a, | ||
115 | 'GDTR_WRITE': 0x06b, | ||
116 | 'LDTR_WRITE': 0x06c, | ||
117 | 'TR_WRITE': 0x06d, | ||
118 | 'RDTSC': 0x06e, | ||
119 | 'RDPMC': 0x06f, | ||
120 | 'PUSHF': 0x070, | ||
121 | 'POPF': 0x071, | ||
122 | 'CPUID': 0x072, | ||
123 | 'RSM': 0x073, | ||
124 | 'IRET': 0x074, | ||
125 | 'SWINT': 0x075, | ||
126 | 'INVD': 0x076, | ||
127 | 'PAUSE': 0x077, | ||
128 | 'HLT': 0x078, | ||
129 | 'INVLPG': 0x079, | ||
130 | 'INVLPGA': 0x07a, | ||
131 | 'IOIO': 0x07b, | ||
132 | 'MSR': 0x07c, | ||
133 | 'TASK_SWITCH': 0x07d, | ||
134 | 'FERR_FREEZE': 0x07e, | ||
135 | 'SHUTDOWN': 0x07f, | ||
136 | 'VMRUN': 0x080, | ||
137 | 'VMMCALL': 0x081, | ||
138 | 'VMLOAD': 0x082, | ||
139 | 'VMSAVE': 0x083, | ||
140 | 'STGI': 0x084, | ||
141 | 'CLGI': 0x085, | ||
142 | 'SKINIT': 0x086, | ||
143 | 'RDTSCP': 0x087, | ||
144 | 'ICEBP': 0x088, | ||
145 | 'WBINVD': 0x089, | ||
146 | 'MONITOR': 0x08a, | ||
147 | 'MWAIT': 0x08b, | ||
148 | 'MWAIT_COND': 0x08c, | ||
149 | 'XSETBV': 0x08d, | ||
150 | 'NPF': 0x400, | ||
151 | } | ||
152 | |||
153 | # EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h) | ||
154 | AARCH64_EXIT_REASONS = { | ||
155 | 'UNKNOWN': 0x00, | ||
156 | 'WFI': 0x01, | ||
157 | 'CP15_32': 0x03, | ||
158 | 'CP15_64': 0x04, | ||
159 | 'CP14_MR': 0x05, | ||
160 | 'CP14_LS': 0x06, | ||
161 | 'FP_ASIMD': 0x07, | ||
162 | 'CP10_ID': 0x08, | ||
163 | 'CP14_64': 0x0C, | ||
164 | 'ILL_ISS': 0x0E, | ||
165 | 'SVC32': 0x11, | ||
166 | 'HVC32': 0x12, | ||
167 | 'SMC32': 0x13, | ||
168 | 'SVC64': 0x15, | ||
169 | 'HVC64': 0x16, | ||
170 | 'SMC64': 0x17, | ||
171 | 'SYS64': 0x18, | ||
172 | 'IABT': 0x20, | ||
173 | 'IABT_HYP': 0x21, | ||
174 | 'PC_ALIGN': 0x22, | ||
175 | 'DABT': 0x24, | ||
176 | 'DABT_HYP': 0x25, | ||
177 | 'SP_ALIGN': 0x26, | ||
178 | 'FP_EXC32': 0x28, | ||
179 | 'FP_EXC64': 0x2C, | ||
180 | 'SERROR': 0x2F, | ||
181 | 'BREAKPT': 0x30, | ||
182 | 'BREAKPT_HYP': 0x31, | ||
183 | 'SOFTSTP': 0x32, | ||
184 | 'SOFTSTP_HYP': 0x33, | ||
185 | 'WATCHPT': 0x34, | ||
186 | 'WATCHPT_HYP': 0x35, | ||
187 | 'BKPT32': 0x38, | ||
188 | 'VECTOR32': 0x3A, | ||
189 | 'BRK64': 0x3C, | ||
190 | } | ||
191 | |||
192 | # From include/uapi/linux/kvm.h, KVM_EXIT_xxx | ||
193 | USERSPACE_EXIT_REASONS = { | ||
194 | 'UNKNOWN': 0, | ||
195 | 'EXCEPTION': 1, | ||
196 | 'IO': 2, | ||
197 | 'HYPERCALL': 3, | ||
198 | 'DEBUG': 4, | ||
199 | 'HLT': 5, | ||
200 | 'MMIO': 6, | ||
201 | 'IRQ_WINDOW_OPEN': 7, | ||
202 | 'SHUTDOWN': 8, | ||
203 | 'FAIL_ENTRY': 9, | ||
204 | 'INTR': 10, | ||
205 | 'SET_TPR': 11, | ||
206 | 'TPR_ACCESS': 12, | ||
207 | 'S390_SIEIC': 13, | ||
208 | 'S390_RESET': 14, | ||
209 | 'DCR': 15, | ||
210 | 'NMI': 16, | ||
211 | 'INTERNAL_ERROR': 17, | ||
212 | 'OSI': 18, | ||
213 | 'PAPR_HCALL': 19, | ||
214 | 'S390_UCONTROL': 20, | ||
215 | 'WATCHDOG': 21, | ||
216 | 'S390_TSCH': 22, | ||
217 | 'EPR': 23, | ||
218 | 'SYSTEM_EVENT': 24, | ||
219 | } | ||
220 | |||
221 | IOCTL_NUMBERS = { | ||
222 | 'SET_FILTER': 0x40082406, | ||
223 | 'ENABLE': 0x00002400, | ||
224 | 'DISABLE': 0x00002401, | ||
225 | 'RESET': 0x00002403, | ||
226 | } | ||
227 | |||
228 | class Arch(object): | ||
229 | """Encapsulates global architecture specific data. | ||
230 | |||
231 | Contains the performance event open syscall and ioctl numbers, as | ||
232 | well as the VM exit reasons for the architecture it runs on. | ||
233 | |||
234 | """ | ||
235 | @staticmethod | ||
236 | def get_arch(): | ||
237 | machine = os.uname()[4] | ||
238 | |||
239 | if machine.startswith('ppc'): | ||
240 | return ArchPPC() | ||
241 | elif machine.startswith('aarch64'): | ||
242 | return ArchA64() | ||
243 | elif machine.startswith('s390'): | ||
244 | return ArchS390() | ||
245 | else: | ||
246 | # X86_64 | ||
247 | for line in open('/proc/cpuinfo'): | ||
248 | if not line.startswith('flags'): | ||
249 | continue | ||
250 | |||
251 | flags = line.split() | ||
252 | if 'vmx' in flags: | ||
253 | return ArchX86(VMX_EXIT_REASONS) | ||
254 | if 'svm' in flags: | ||
255 | return ArchX86(SVM_EXIT_REASONS) | ||
256 | return | ||
257 | |||
258 | class ArchX86(Arch): | ||
259 | def __init__(self, exit_reasons): | ||
260 | self.sc_perf_evt_open = 298 | ||
261 | self.ioctl_numbers = IOCTL_NUMBERS | ||
262 | self.exit_reasons = exit_reasons | ||
263 | |||
264 | class ArchPPC(Arch): | ||
265 | def __init__(self): | ||
266 | self.sc_perf_evt_open = 319 | ||
267 | self.ioctl_numbers = IOCTL_NUMBERS | ||
268 | self.ioctl_numbers['ENABLE'] = 0x20002400 | ||
269 | self.ioctl_numbers['DISABLE'] = 0x20002401 | ||
270 | self.ioctl_numbers['RESET'] = 0x20002403 | ||
271 | |||
272 | # PPC comes in 32 and 64 bit and some generated ioctl | ||
273 | # numbers depend on the wordsize. | ||
274 | char_ptr_size = ctypes.sizeof(ctypes.c_char_p) | ||
275 | self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 | ||
276 | self.exit_reasons = {} | ||
277 | |||
278 | class ArchA64(Arch): | ||
279 | def __init__(self): | ||
280 | self.sc_perf_evt_open = 241 | ||
281 | self.ioctl_numbers = IOCTL_NUMBERS | ||
282 | self.exit_reasons = AARCH64_EXIT_REASONS | ||
283 | |||
284 | class ArchS390(Arch): | ||
285 | def __init__(self): | ||
286 | self.sc_perf_evt_open = 331 | ||
287 | self.ioctl_numbers = IOCTL_NUMBERS | ||
288 | self.exit_reasons = None | ||
289 | |||
290 | ARCH = Arch.get_arch() | ||
291 | |||
292 | |||
293 | def walkdir(path): | ||
294 | """Returns os.walk() data for specified directory. | ||
295 | |||
296 | As it is only a wrapper it returns the same 3-tuple of (dirpath, | ||
297 | dirnames, filenames). | ||
298 | """ | ||
299 | return next(os.walk(path)) | ||
300 | |||
301 | |||
302 | def parse_int_list(list_string): | ||
303 | """Returns an int list from a string of comma separated integers and | ||
304 | integer ranges.""" | ||
305 | integers = [] | ||
306 | members = list_string.split(',') | ||
307 | |||
308 | for member in members: | ||
309 | if '-' not in member: | ||
310 | integers.append(int(member)) | ||
311 | else: | ||
312 | int_range = member.split('-') | ||
313 | integers.extend(range(int(int_range[0]), | ||
314 | int(int_range[1]) + 1)) | ||
315 | |||
316 | return integers | ||
317 | |||
318 | |||
319 | def get_online_cpus(): | ||
320 | """Returns a list of cpu id integers.""" | ||
321 | with open('/sys/devices/system/cpu/online') as cpu_list: | ||
322 | cpu_string = cpu_list.readline() | ||
323 | return parse_int_list(cpu_string) | ||
324 | |||
325 | |||
326 | def get_filters(): | ||
327 | """Returns a dict of trace events, their filter ids and | ||
328 | the values that can be filtered. | ||
329 | |||
330 | Trace events can be filtered for special values by setting a | ||
331 | filter string via an ioctl. The string normally has the format | ||
332 | identifier==value. For each filter a new event will be created, to | ||
333 | be able to distinguish the events. | ||
334 | |||
335 | """ | ||
336 | filters = {} | ||
337 | filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) | ||
338 | if ARCH.exit_reasons: | ||
339 | filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) | ||
340 | return filters | ||
341 | |||
342 | libc = ctypes.CDLL('libc.so.6', use_errno=True) | ||
343 | syscall = libc.syscall | ||
344 | |||
345 | class perf_event_attr(ctypes.Structure): | ||
346 | """Struct that holds the necessary data to set up a trace event. | ||
347 | |||
348 | For an extensive explanation see perf_event_open(2) and | ||
349 | include/uapi/linux/perf_event.h, struct perf_event_attr | ||
350 | |||
351 | All fields that are not initialized in the constructor are 0. | ||
352 | |||
353 | """ | ||
354 | _fields_ = [('type', ctypes.c_uint32), | ||
355 | ('size', ctypes.c_uint32), | ||
356 | ('config', ctypes.c_uint64), | ||
357 | ('sample_freq', ctypes.c_uint64), | ||
358 | ('sample_type', ctypes.c_uint64), | ||
359 | ('read_format', ctypes.c_uint64), | ||
360 | ('flags', ctypes.c_uint64), | ||
361 | ('wakeup_events', ctypes.c_uint32), | ||
362 | ('bp_type', ctypes.c_uint32), | ||
363 | ('bp_addr', ctypes.c_uint64), | ||
364 | ('bp_len', ctypes.c_uint64), | ||
365 | ] | ||
366 | |||
367 | def __init__(self): | ||
368 | super(self.__class__, self).__init__() | ||
369 | self.type = PERF_TYPE_TRACEPOINT | ||
370 | self.size = ctypes.sizeof(self) | ||
371 | self.read_format = PERF_FORMAT_GROUP | ||
372 | |||
373 | def perf_event_open(attr, pid, cpu, group_fd, flags): | ||
374 | """Wrapper for the sys_perf_evt_open() syscall. | ||
375 | |||
376 | Used to set up performance events, returns a file descriptor or -1 | ||
377 | on error. | ||
378 | |||
379 | Attributes are: | ||
380 | - syscall number | ||
381 | - struct perf_event_attr * | ||
382 | - pid or -1 to monitor all pids | ||
383 | - cpu number or -1 to monitor all cpus | ||
384 | - The file descriptor of the group leader or -1 to create a group. | ||
385 | - flags | ||
386 | |||
387 | """ | ||
388 | return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), | ||
389 | ctypes.c_int(pid), ctypes.c_int(cpu), | ||
390 | ctypes.c_int(group_fd), ctypes.c_long(flags)) | ||
391 | |||
392 | PERF_TYPE_TRACEPOINT = 2 | ||
393 | PERF_FORMAT_GROUP = 1 << 3 | ||
394 | |||
395 | PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' | ||
396 | PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' | ||
397 | |||
398 | class Group(object): | ||
399 | """Represents a perf event group.""" | ||
400 | |||
401 | def __init__(self): | ||
402 | self.events = [] | ||
403 | |||
404 | def add_event(self, event): | ||
405 | self.events.append(event) | ||
406 | |||
407 | def read(self): | ||
408 | """Returns a dict with 'event name: value' for all events in the | ||
409 | group. | ||
410 | |||
411 | Values are read by reading from the file descriptor of the | ||
412 | event that is the group leader. See perf_event_open(2) for | ||
413 | details. | ||
414 | |||
415 | Read format for the used event configuration is: | ||
416 | struct read_format { | ||
417 | u64 nr; /* The number of events */ | ||
418 | struct { | ||
419 | u64 value; /* The value of the event */ | ||
420 | } values[nr]; | ||
421 | }; | ||
422 | |||
423 | """ | ||
424 | length = 8 * (1 + len(self.events)) | ||
425 | read_format = 'xxxxxxxx' + 'Q' * len(self.events) | ||
426 | return dict(zip([event.name for event in self.events], | ||
427 | struct.unpack(read_format, | ||
428 | os.read(self.events[0].fd, length)))) | ||
429 | |||
430 | class Event(object): | ||
431 | """Represents a performance event and manages its life cycle.""" | ||
432 | def __init__(self, name, group, trace_cpu, trace_pid, trace_point, | ||
433 | trace_filter, trace_set='kvm'): | ||
434 | self.name = name | ||
435 | self.fd = None | ||
436 | self.setup_event(group, trace_cpu, trace_pid, trace_point, | ||
437 | trace_filter, trace_set) | ||
438 | |||
439 | def __del__(self): | ||
440 | """Closes the event's file descriptor. | ||
441 | |||
442 | As no python file object was created for the file descriptor, | ||
443 | python will not reference count the descriptor and will not | ||
444 | close it itself automatically, so we do it. | ||
445 | |||
446 | """ | ||
447 | if self.fd: | ||
448 | os.close(self.fd) | ||
449 | |||
450 | def setup_event_attribute(self, trace_set, trace_point): | ||
451 | """Returns an initialized ctype perf_event_attr struct.""" | ||
452 | |||
453 | id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, | ||
454 | trace_point, 'id') | ||
455 | |||
456 | event_attr = perf_event_attr() | ||
457 | event_attr.config = int(open(id_path).read()) | ||
458 | return event_attr | ||
459 | |||
460 | def setup_event(self, group, trace_cpu, trace_pid, trace_point, | ||
461 | trace_filter, trace_set): | ||
462 | """Sets up the perf event in Linux. | ||
463 | |||
464 | Issues the syscall to register the event in the kernel and | ||
465 | then sets the optional filter. | ||
466 | |||
467 | """ | ||
468 | |||
469 | event_attr = self.setup_event_attribute(trace_set, trace_point) | ||
470 | |||
471 | # First event will be group leader. | ||
472 | group_leader = -1 | ||
473 | |||
474 | # All others have to pass the leader's descriptor instead. | ||
475 | if group.events: | ||
476 | group_leader = group.events[0].fd | ||
477 | |||
478 | fd = perf_event_open(event_attr, trace_pid, | ||
479 | trace_cpu, group_leader, 0) | ||
480 | if fd == -1: | ||
481 | err = ctypes.get_errno() | ||
482 | raise OSError(err, os.strerror(err), | ||
483 | 'while calling sys_perf_event_open().') | ||
484 | |||
485 | if trace_filter: | ||
486 | fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'], | ||
487 | trace_filter) | ||
488 | |||
489 | self.fd = fd | ||
490 | |||
491 | def enable(self): | ||
492 | """Enables the trace event in the kernel. | ||
493 | |||
494 | Enabling the group leader makes reading counters from it and the | ||
495 | events under it possible. | ||
496 | |||
497 | """ | ||
498 | fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0) | ||
499 | |||
500 | def disable(self): | ||
501 | """Disables the trace event in the kernel. | ||
502 | |||
503 | Disabling the group leader makes reading all counters under it | ||
504 | impossible. | ||
505 | |||
506 | """ | ||
507 | fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0) | ||
508 | |||
509 | def reset(self): | ||
510 | """Resets the count of the trace event in the kernel.""" | ||
511 | fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) | ||
512 | |||
513 | class TracepointProvider(object): | ||
514 | """Data provider for the stats class. | ||
515 | |||
516 | Manages the events/groups from which it acquires its data. | ||
517 | |||
518 | """ | ||
519 | def __init__(self): | ||
520 | self.group_leaders = [] | ||
521 | self.filters = get_filters() | ||
522 | self._fields = self.get_available_fields() | ||
523 | self._pid = 0 | ||
524 | |||
525 | def get_available_fields(self): | ||
526 | """Returns a list of available event's of format 'event name(filter | ||
527 | name)'. | ||
528 | |||
529 | All available events have directories under | ||
530 | /sys/kernel/debug/tracing/events/ which export information | ||
531 | about the specific event. Therefore, listing the dirs gives us | ||
532 | a list of all available events. | ||
533 | |||
534 | Some events like the vm exit reasons can be filtered for | ||
535 | specific values. To take account for that, the routine below | ||
536 | creates special fields with the following format: | ||
537 | event name(filter name) | ||
538 | |||
539 | """ | ||
540 | path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') | ||
541 | fields = walkdir(path)[1] | ||
542 | extra = [] | ||
543 | for field in fields: | ||
544 | if field in self.filters: | ||
545 | filter_name_, filter_dicts = self.filters[field] | ||
546 | for name in filter_dicts: | ||
547 | extra.append(field + '(' + name + ')') | ||
548 | fields += extra | ||
549 | return fields | ||
550 | |||
551 | def setup_traces(self): | ||
552 | """Creates all event and group objects needed to be able to retrieve | ||
553 | data.""" | ||
554 | if self._pid > 0: | ||
555 | # Fetch list of all threads of the monitored pid, as qemu | ||
556 | # starts a thread for each vcpu. | ||
557 | path = os.path.join('/proc', str(self._pid), 'task') | ||
558 | groupids = walkdir(path)[1] | ||
559 | else: | ||
560 | groupids = get_online_cpus() | ||
561 | |||
562 | # The constant is needed as a buffer for python libs, std | ||
563 | # streams and other files that the script opens. | ||
564 | newlim = len(groupids) * len(self._fields) + 50 | ||
565 | try: | ||
566 | softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) | ||
567 | |||
568 | if hardlim < newlim: | ||
569 | # Now we need CAP_SYS_RESOURCE, to increase the hard limit. | ||
570 | resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim)) | ||
571 | else: | ||
572 | # Raising the soft limit is sufficient. | ||
573 | resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim)) | ||
574 | |||
575 | except ValueError: | ||
576 | sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim)) | ||
577 | |||
578 | for groupid in groupids: | ||
579 | group = Group() | ||
580 | for name in self._fields: | ||
581 | tracepoint = name | ||
582 | tracefilter = None | ||
583 | match = re.match(r'(.*)\((.*)\)', name) | ||
584 | if match: | ||
585 | tracepoint, sub = match.groups() | ||
586 | tracefilter = ('%s==%d\0' % | ||
587 | (self.filters[tracepoint][0], | ||
588 | self.filters[tracepoint][1][sub])) | ||
589 | |||
590 | # From perf_event_open(2): | ||
591 | # pid > 0 and cpu == -1 | ||
592 | # This measures the specified process/thread on any CPU. | ||
593 | # | ||
594 | # pid == -1 and cpu >= 0 | ||
595 | # This measures all processes/threads on the specified CPU. | ||
596 | trace_cpu = groupid if self._pid == 0 else -1 | ||
597 | trace_pid = int(groupid) if self._pid != 0 else -1 | ||
598 | |||
599 | group.add_event(Event(name=name, | ||
600 | group=group, | ||
601 | trace_cpu=trace_cpu, | ||
602 | trace_pid=trace_pid, | ||
603 | trace_point=tracepoint, | ||
604 | trace_filter=tracefilter)) | ||
605 | |||
606 | self.group_leaders.append(group) | ||
607 | |||
608 | def available_fields(self): | ||
609 | return self.get_available_fields() | ||
610 | |||
611 | @property | ||
612 | def fields(self): | ||
613 | return self._fields | ||
614 | |||
615 | @fields.setter | ||
616 | def fields(self, fields): | ||
617 | """Enables/disables the (un)wanted events""" | ||
618 | self._fields = fields | ||
619 | for group in self.group_leaders: | ||
620 | for index, event in enumerate(group.events): | ||
621 | if event.name in fields: | ||
622 | event.reset() | ||
623 | event.enable() | ||
624 | else: | ||
625 | # Do not disable the group leader. | ||
626 | # It would disable all of its events. | ||
627 | if index != 0: | ||
628 | event.disable() | ||
629 | |||
630 | @property | ||
631 | def pid(self): | ||
632 | return self._pid | ||
633 | |||
634 | @pid.setter | ||
635 | def pid(self, pid): | ||
636 | """Changes the monitored pid by setting new traces.""" | ||
637 | self._pid = pid | ||
638 | # The garbage collector will get rid of all Event/Group | ||
639 | # objects and open files after removing the references. | ||
640 | self.group_leaders = [] | ||
641 | self.setup_traces() | ||
642 | self.fields = self._fields | ||
643 | |||
644 | def read(self): | ||
645 | """Returns 'event name: current value' for all enabled events.""" | ||
646 | ret = defaultdict(int) | ||
647 | for group in self.group_leaders: | ||
648 | for name, val in group.read().iteritems(): | ||
649 | if name in self._fields: | ||
650 | ret[name] += val | ||
651 | return ret | ||
652 | |||
653 | class DebugfsProvider(object): | ||
654 | """Provides data from the files that KVM creates in the kvm debugfs | ||
655 | folder.""" | ||
656 | def __init__(self): | ||
657 | self._fields = self.get_available_fields() | ||
658 | self._pid = 0 | ||
659 | self.do_read = True | ||
660 | |||
661 | def get_available_fields(self): | ||
662 | """"Returns a list of available fields. | ||
663 | |||
664 | The fields are all available KVM debugfs files | ||
665 | |||
666 | """ | ||
667 | return walkdir(PATH_DEBUGFS_KVM)[2] | ||
668 | |||
669 | @property | ||
670 | def fields(self): | ||
671 | return self._fields | ||
672 | |||
673 | @fields.setter | ||
674 | def fields(self, fields): | ||
675 | self._fields = fields | ||
676 | |||
677 | @property | ||
678 | def pid(self): | ||
679 | return self._pid | ||
680 | |||
681 | @pid.setter | ||
682 | def pid(self, pid): | ||
683 | if pid != 0: | ||
684 | self._pid = pid | ||
685 | |||
686 | vms = walkdir(PATH_DEBUGFS_KVM)[1] | ||
687 | if len(vms) == 0: | ||
688 | self.do_read = False | ||
689 | |||
690 | self.paths = filter(lambda x: "{}-".format(pid) in x, vms) | ||
691 | |||
692 | else: | ||
693 | self.paths = [''] | ||
694 | self.do_read = True | ||
695 | |||
696 | def read(self): | ||
697 | """Returns a dict with format:'file name / field -> current value'.""" | ||
698 | results = {} | ||
699 | |||
700 | # If no debugfs filtering support is available, then don't read. | ||
701 | if not self.do_read: | ||
702 | return results | ||
703 | |||
704 | for path in self.paths: | ||
705 | for field in self._fields: | ||
706 | results[field] = results.get(field, 0) \ | ||
707 | + self.read_field(field, path) | ||
708 | |||
709 | return results | ||
710 | |||
711 | def read_field(self, field, path): | ||
712 | """Returns the value of a single field from a specific VM.""" | ||
713 | try: | ||
714 | return int(open(os.path.join(PATH_DEBUGFS_KVM, | ||
715 | path, | ||
716 | field)) | ||
717 | .read()) | ||
718 | except IOError: | ||
719 | return 0 | ||
720 | |||
721 | class Stats(object): | ||
722 | """Manages the data providers and the data they provide. | ||
723 | |||
724 | It is used to set filters on the provider's data and collect all | ||
725 | provider data. | ||
726 | |||
727 | """ | ||
728 | def __init__(self, providers, pid, fields=None): | ||
729 | self.providers = providers | ||
730 | self._pid_filter = pid | ||
731 | self._fields_filter = fields | ||
732 | self.values = {} | ||
733 | self.update_provider_pid() | ||
734 | self.update_provider_filters() | ||
735 | |||
736 | def update_provider_filters(self): | ||
737 | """Propagates fields filters to providers.""" | ||
738 | def wanted(key): | ||
739 | if not self._fields_filter: | ||
740 | return True | ||
741 | return re.match(self._fields_filter, key) is not None | ||
742 | |||
743 | # As we reset the counters when updating the fields we can | ||
744 | # also clear the cache of old values. | ||
745 | self.values = {} | ||
746 | for provider in self.providers: | ||
747 | provider_fields = [key for key in provider.get_available_fields() | ||
748 | if wanted(key)] | ||
749 | provider.fields = provider_fields | ||
750 | |||
751 | def update_provider_pid(self): | ||
752 | """Propagates pid filters to providers.""" | ||
753 | for provider in self.providers: | ||
754 | provider.pid = self._pid_filter | ||
755 | |||
756 | @property | ||
757 | def fields_filter(self): | ||
758 | return self._fields_filter | ||
759 | |||
760 | @fields_filter.setter | ||
761 | def fields_filter(self, fields_filter): | ||
762 | self._fields_filter = fields_filter | ||
763 | self.update_provider_filters() | ||
764 | |||
765 | @property | ||
766 | def pid_filter(self): | ||
767 | return self._pid_filter | ||
768 | |||
769 | @pid_filter.setter | ||
770 | def pid_filter(self, pid): | ||
771 | self._pid_filter = pid | ||
772 | self.values = {} | ||
773 | self.update_provider_pid() | ||
774 | |||
775 | def get(self): | ||
776 | """Returns a dict with field -> (value, delta to last value) of all | ||
777 | provider data.""" | ||
778 | for provider in self.providers: | ||
779 | new = provider.read() | ||
780 | for key in provider.fields: | ||
781 | oldval = self.values.get(key, (0, 0)) | ||
782 | newval = new.get(key, 0) | ||
783 | newdelta = None | ||
784 | if oldval is not None: | ||
785 | newdelta = newval - oldval[0] | ||
786 | self.values[key] = (newval, newdelta) | ||
787 | return self.values | ||
788 | |||
789 | LABEL_WIDTH = 40 | ||
790 | NUMBER_WIDTH = 10 | ||
791 | |||
792 | class Tui(object): | ||
793 | """Instruments curses to draw a nice text ui.""" | ||
794 | def __init__(self, stats): | ||
795 | self.stats = stats | ||
796 | self.screen = None | ||
797 | self.drilldown = False | ||
798 | self.update_drilldown() | ||
799 | |||
800 | def __enter__(self): | ||
801 | """Initialises curses for later use. Based on curses.wrapper | ||
802 | implementation from the Python standard library.""" | ||
803 | self.screen = curses.initscr() | ||
804 | curses.noecho() | ||
805 | curses.cbreak() | ||
806 | |||
807 | # The try/catch works around a minor bit of | ||
808 | # over-conscientiousness in the curses module, the error | ||
809 | # return from C start_color() is ignorable. | ||
810 | try: | ||
811 | curses.start_color() | ||
812 | except: | ||
813 | pass | ||
814 | |||
815 | curses.use_default_colors() | ||
816 | return self | ||
817 | |||
818 | def __exit__(self, *exception): | ||
819 | """Resets the terminal to its normal state. Based on curses.wrappre | ||
820 | implementation from the Python standard library.""" | ||
821 | if self.screen: | ||
822 | self.screen.keypad(0) | ||
823 | curses.echo() | ||
824 | curses.nocbreak() | ||
825 | curses.endwin() | ||
826 | |||
827 | def update_drilldown(self): | ||
828 | """Sets or removes a filter that only allows fields without braces.""" | ||
829 | if not self.stats.fields_filter: | ||
830 | self.stats.fields_filter = r'^[^\(]*$' | ||
831 | |||
832 | elif self.stats.fields_filter == r'^[^\(]*$': | ||
833 | self.stats.fields_filter = None | ||
834 | |||
835 | def update_pid(self, pid): | ||
836 | """Propagates pid selection to stats object.""" | ||
837 | self.stats.pid_filter = pid | ||
838 | |||
839 | def refresh(self, sleeptime): | ||
840 | """Refreshes on-screen data.""" | ||
841 | self.screen.erase() | ||
842 | if self.stats.pid_filter > 0: | ||
843 | self.screen.addstr(0, 0, 'kvm statistics - pid {0}' | ||
844 | .format(self.stats.pid_filter), | ||
845 | curses.A_BOLD) | ||
846 | else: | ||
847 | self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) | ||
848 | self.screen.addstr(2, 1, 'Event') | ||
849 | self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - | ||
850 | len('Total'), 'Total') | ||
851 | self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - | ||
852 | len('Current'), 'Current') | ||
853 | row = 3 | ||
854 | stats = self.stats.get() | ||
855 | def sortkey(x): | ||
856 | if stats[x][1]: | ||
857 | return (-stats[x][1], -stats[x][0]) | ||
858 | else: | ||
859 | return (0, -stats[x][0]) | ||
860 | for key in sorted(stats.keys(), key=sortkey): | ||
861 | |||
862 | if row >= self.screen.getmaxyx()[0]: | ||
863 | break | ||
864 | values = stats[key] | ||
865 | if not values[0] and not values[1]: | ||
866 | break | ||
867 | col = 1 | ||
868 | self.screen.addstr(row, col, key) | ||
869 | col += LABEL_WIDTH | ||
870 | self.screen.addstr(row, col, '%10d' % (values[0],)) | ||
871 | col += NUMBER_WIDTH | ||
872 | if values[1] is not None: | ||
873 | self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) | ||
874 | row += 1 | ||
875 | self.screen.refresh() | ||
876 | |||
877 | def show_filter_selection(self): | ||
878 | """Draws filter selection mask. | ||
879 | |||
880 | Asks for a valid regex and sets the fields filter accordingly. | ||
881 | |||
882 | """ | ||
883 | while True: | ||
884 | self.screen.erase() | ||
885 | self.screen.addstr(0, 0, | ||
886 | "Show statistics for events matching a regex.", | ||
887 | curses.A_BOLD) | ||
888 | self.screen.addstr(2, 0, | ||
889 | "Current regex: {0}" | ||
890 | .format(self.stats.fields_filter)) | ||
891 | self.screen.addstr(3, 0, "New regex: ") | ||
892 | curses.echo() | ||
893 | regex = self.screen.getstr() | ||
894 | curses.noecho() | ||
895 | if len(regex) == 0: | ||
896 | return | ||
897 | try: | ||
898 | re.compile(regex) | ||
899 | self.stats.fields_filter = regex | ||
900 | return | ||
901 | except re.error: | ||
902 | continue | ||
903 | |||
904 | def show_vm_selection(self): | ||
905 | """Draws PID selection mask. | ||
906 | |||
907 | Asks for a pid until a valid pid or 0 has been entered. | ||
908 | |||
909 | """ | ||
910 | while True: | ||
911 | self.screen.erase() | ||
912 | self.screen.addstr(0, 0, | ||
913 | 'Show statistics for specific pid.', | ||
914 | curses.A_BOLD) | ||
915 | self.screen.addstr(1, 0, | ||
916 | 'This might limit the shown data to the trace ' | ||
917 | 'statistics.') | ||
918 | |||
919 | curses.echo() | ||
920 | self.screen.addstr(3, 0, "Pid [0 or pid]: ") | ||
921 | pid = self.screen.getstr() | ||
922 | curses.noecho() | ||
923 | |||
924 | try: | ||
925 | pid = int(pid) | ||
926 | |||
927 | if pid == 0: | ||
928 | self.update_pid(pid) | ||
929 | break | ||
930 | else: | ||
931 | if not os.path.isdir(os.path.join('/proc/', str(pid))): | ||
932 | continue | ||
933 | else: | ||
934 | self.update_pid(pid) | ||
935 | break | ||
936 | |||
937 | except ValueError: | ||
938 | continue | ||
939 | |||
940 | def show_stats(self): | ||
941 | """Refreshes the screen and processes user input.""" | ||
942 | sleeptime = 0.25 | ||
943 | while True: | ||
944 | self.refresh(sleeptime) | ||
945 | curses.halfdelay(int(sleeptime * 10)) | ||
946 | sleeptime = 3 | ||
947 | try: | ||
948 | char = self.screen.getkey() | ||
949 | if char == 'x': | ||
950 | self.drilldown = not self.drilldown | ||
951 | self.update_drilldown() | ||
952 | if char == 'q': | ||
953 | break | ||
954 | if char == 'f': | ||
955 | self.show_filter_selection() | ||
956 | if char == 'p': | ||
957 | self.show_vm_selection() | ||
958 | except KeyboardInterrupt: | ||
959 | break | ||
960 | except curses.error: | ||
961 | continue | ||
962 | |||
963 | def batch(stats): | ||
964 | """Prints statistics in a key, value format.""" | ||
965 | s = stats.get() | ||
966 | time.sleep(1) | ||
967 | s = stats.get() | ||
968 | for key in sorted(s.keys()): | ||
969 | values = s[key] | ||
970 | print '%-42s%10d%10d' % (key, values[0], values[1]) | ||
971 | |||
972 | def log(stats): | ||
973 | """Prints statistics as reiterating key block, multiple value blocks.""" | ||
974 | keys = sorted(stats.get().iterkeys()) | ||
975 | def banner(): | ||
976 | for k in keys: | ||
977 | print '%s' % k, | ||
978 | |||
979 | def statline(): | ||
980 | s = stats.get() | ||
981 | for k in keys: | ||
982 | print ' %9d' % s[k][1], | ||
983 | |||
984 | line = 0 | ||
985 | banner_repeat = 20 | ||
986 | while True: | ||
987 | time.sleep(1) | ||
988 | if line % banner_repeat == 0: | ||
989 | banner() | ||
990 | statline() | ||
991 | line += 1 | ||
992 | |||
993 | def get_options(): | ||
994 | """Returns processed program arguments.""" | ||
995 | description_text = """ | ||
996 | This script displays various statistics about VMs running under KVM. | ||
997 | The statistics are gathered from the KVM debugfs entries and / or the | ||
998 | currently available perf traces. | ||
999 | |||
1000 | The monitoring takes additional cpu cycles and might affect the VM's | ||
1001 | performance. | ||
1002 | |||
1003 | Requirements: | ||
1004 | - Access to: | ||
1005 | /sys/kernel/debug/kvm | ||
1006 | /sys/kernel/debug/trace/events/* | ||
1007 | /proc/pid/task | ||
1008 | - /proc/sys/kernel/perf_event_paranoid < 1 if user has no | ||
1009 | CAP_SYS_ADMIN and perf events are used. | ||
1010 | - CAP_SYS_RESOURCE if the hard limit is not high enough to allow | ||
1011 | the large number of files that are possibly opened. | ||
1012 | """ | ||
1013 | |||
1014 | class PlainHelpFormatter(optparse.IndentedHelpFormatter): | ||
1015 | def format_description(self, description): | ||
1016 | if description: | ||
1017 | return description + "\n" | ||
1018 | else: | ||
1019 | return "" | ||
1020 | |||
1021 | optparser = optparse.OptionParser(description=description_text, | ||
1022 | formatter=PlainHelpFormatter()) | ||
1023 | optparser.add_option('-1', '--once', '--batch', | ||
1024 | action='store_true', | ||
1025 | default=False, | ||
1026 | dest='once', | ||
1027 | help='run in batch mode for one second', | ||
1028 | ) | ||
1029 | optparser.add_option('-l', '--log', | ||
1030 | action='store_true', | ||
1031 | default=False, | ||
1032 | dest='log', | ||
1033 | help='run in logging mode (like vmstat)', | ||
1034 | ) | ||
1035 | optparser.add_option('-t', '--tracepoints', | ||
1036 | action='store_true', | ||
1037 | default=False, | ||
1038 | dest='tracepoints', | ||
1039 | help='retrieve statistics from tracepoints', | ||
1040 | ) | ||
1041 | optparser.add_option('-d', '--debugfs', | ||
1042 | action='store_true', | ||
1043 | default=False, | ||
1044 | dest='debugfs', | ||
1045 | help='retrieve statistics from debugfs', | ||
1046 | ) | ||
1047 | optparser.add_option('-f', '--fields', | ||
1048 | action='store', | ||
1049 | default=None, | ||
1050 | dest='fields', | ||
1051 | help='fields to display (regex)', | ||
1052 | ) | ||
1053 | optparser.add_option('-p', '--pid', | ||
1054 | action='store', | ||
1055 | default=0, | ||
1056 | type=int, | ||
1057 | dest='pid', | ||
1058 | help='restrict statistics to pid', | ||
1059 | ) | ||
1060 | (options, _) = optparser.parse_args(sys.argv) | ||
1061 | return options | ||
1062 | |||
1063 | def get_providers(options): | ||
1064 | """Returns a list of data providers depending on the passed options.""" | ||
1065 | providers = [] | ||
1066 | |||
1067 | if options.tracepoints: | ||
1068 | providers.append(TracepointProvider()) | ||
1069 | if options.debugfs: | ||
1070 | providers.append(DebugfsProvider()) | ||
1071 | if len(providers) == 0: | ||
1072 | providers.append(TracepointProvider()) | ||
1073 | |||
1074 | return providers | ||
1075 | |||
1076 | def check_access(options): | ||
1077 | """Exits if the current user can't access all needed directories.""" | ||
1078 | if not os.path.exists('/sys/kernel/debug'): | ||
1079 | sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') | ||
1080 | sys.exit(1) | ||
1081 | |||
1082 | if not os.path.exists(PATH_DEBUGFS_KVM): | ||
1083 | sys.stderr.write("Please make sure, that debugfs is mounted and " | ||
1084 | "readable by the current user:\n" | ||
1085 | "('mount -t debugfs debugfs /sys/kernel/debug')\n" | ||
1086 | "Also ensure, that the kvm modules are loaded.\n") | ||
1087 | sys.exit(1) | ||
1088 | |||
1089 | if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints | ||
1090 | or not options.debugfs): | ||
1091 | sys.stderr.write("Please enable CONFIG_TRACING in your kernel " | ||
1092 | "when using the option -t (default).\n" | ||
1093 | "If it is enabled, make {0} readable by the " | ||
1094 | "current user.\n" | ||
1095 | .format(PATH_DEBUGFS_TRACING)) | ||
1096 | if options.tracepoints: | ||
1097 | sys.exit(1) | ||
1098 | |||
1099 | sys.stderr.write("Falling back to debugfs statistics!\n") | ||
1100 | options.debugfs = True | ||
1101 | sleep(5) | ||
1102 | |||
1103 | return options | ||
1104 | |||
1105 | def main(): | ||
1106 | options = get_options() | ||
1107 | options = check_access(options) | ||
1108 | |||
1109 | if (options.pid > 0 and | ||
1110 | not os.path.isdir(os.path.join('/proc/', | ||
1111 | str(options.pid)))): | ||
1112 | sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') | ||
1113 | sys.exit('Specified pid does not exist.') | ||
1114 | |||
1115 | providers = get_providers(options) | ||
1116 | stats = Stats(providers, options.pid, fields=options.fields) | ||
1117 | |||
1118 | if options.log: | ||
1119 | log(stats) | ||
1120 | elif not options.once: | ||
1121 | with Tui(stats) as tui: | ||
1122 | tui.show_stats() | ||
1123 | else: | ||
1124 | batch(stats) | ||
1125 | |||
1126 | if __name__ == "__main__": | ||
1127 | main() | ||
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt new file mode 100644 index 000000000000..b92a153d7115 --- /dev/null +++ b/tools/kvm/kvm_stat/kvm_stat.txt | |||
@@ -0,0 +1,63 @@ | |||
1 | kvm_stat(1) | ||
2 | =========== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | kvm_stat - Report KVM kernel module event counters | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | 'kvm_stat' [OPTION]... | ||
12 | |||
13 | DESCRIPTION | ||
14 | ----------- | ||
15 | kvm_stat prints counts of KVM kernel module trace events. These events signify | ||
16 | state transitions such as guest mode entry and exit. | ||
17 | |||
18 | This tool is useful for observing guest behavior from the host perspective. | ||
19 | Often conclusions about performance or buggy behavior can be drawn from the | ||
20 | output. | ||
21 | |||
22 | The set of KVM kernel module trace events may be specific to the kernel version | ||
23 | or architecture. It is best to check the KVM kernel module source code for the | ||
24 | meaning of events. | ||
25 | |||
26 | OPTIONS | ||
27 | ------- | ||
28 | -1:: | ||
29 | --once:: | ||
30 | --batch:: | ||
31 | run in batch mode for one second | ||
32 | |||
33 | -l:: | ||
34 | --log:: | ||
35 | run in logging mode (like vmstat) | ||
36 | |||
37 | -t:: | ||
38 | --tracepoints:: | ||
39 | retrieve statistics from tracepoints | ||
40 | |||
41 | -d:: | ||
42 | --debugfs:: | ||
43 | retrieve statistics from debugfs | ||
44 | |||
45 | -p<pid>:: | ||
46 | --pid=<pid>:: | ||
47 | limit statistics to one virtual machine (pid) | ||
48 | |||
49 | -f<fields>:: | ||
50 | --fields=<fields>:: | ||
51 | fields to display (regex) | ||
52 | |||
53 | -h:: | ||
54 | --help:: | ||
55 | show help message | ||
56 | |||
57 | SEE ALSO | ||
58 | -------- | ||
59 | 'perf'(1), 'trace-cmd'(1) | ||
60 | |||
61 | AUTHOR | ||
62 | ------ | ||
63 | Stefan Hajnoczi <stefanha@redhat.com> | ||
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 6765c7e949f3..f094f3c4ed84 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -30,6 +30,10 @@ INCLUDES := -I$(srctree)/tools/include | |||
30 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | 30 | CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) |
31 | LDFLAGS += -lelf $(LIBSUBCMD) | 31 | LDFLAGS += -lelf $(LIBSUBCMD) |
32 | 32 | ||
33 | # Allow old libelf to be used: | ||
34 | elfshdr := $(shell echo '\#include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) | ||
35 | CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) | ||
36 | |||
33 | AWK = awk | 37 | AWK = awk |
34 | export srctree OUTPUT CFLAGS ARCH AWK | 38 | export srctree OUTPUT CFLAGS ARCH AWK |
35 | include $(srctree)/tools/build/Makefile.include | 39 | include $(srctree)/tools/build/Makefile.include |
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 7f3e00a2f907..aa1ff6596684 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h | |||
@@ -23,6 +23,11 @@ | |||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/hashtable.h> | 24 | #include <linux/hashtable.h> |
25 | 25 | ||
26 | #ifdef LIBELF_USE_DEPRECATED | ||
27 | # define elf_getshdrnum elf_getshnum | ||
28 | # define elf_getshdrstrndx elf_getshstrndx | ||
29 | #endif | ||
30 | |||
26 | struct section { | 31 | struct section { |
27 | struct list_head list; | 32 | struct list_head list; |
28 | GElf_Shdr sh; | 33 | GElf_Shdr sh; |
diff --git a/tools/perf/arch/powerpc/include/perf_regs.h b/tools/perf/arch/powerpc/include/perf_regs.h new file mode 100644 index 000000000000..75de0e92e71e --- /dev/null +++ b/tools/perf/arch/powerpc/include/perf_regs.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef ARCH_PERF_REGS_H | ||
2 | #define ARCH_PERF_REGS_H | ||
3 | |||
4 | #include <stdlib.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <asm/perf_regs.h> | ||
7 | |||
8 | #define PERF_REGS_MASK ((1ULL << PERF_REG_POWERPC_MAX) - 1) | ||
9 | #define PERF_REGS_MAX PERF_REG_POWERPC_MAX | ||
10 | #ifdef __powerpc64__ | ||
11 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 | ||
12 | #else | ||
13 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32 | ||
14 | #endif | ||
15 | |||
16 | #define PERF_REG_IP PERF_REG_POWERPC_NIP | ||
17 | #define PERF_REG_SP PERF_REG_POWERPC_R1 | ||
18 | |||
19 | static const char *reg_names[] = { | ||
20 | [PERF_REG_POWERPC_R0] = "r0", | ||
21 | [PERF_REG_POWERPC_R1] = "r1", | ||
22 | [PERF_REG_POWERPC_R2] = "r2", | ||
23 | [PERF_REG_POWERPC_R3] = "r3", | ||
24 | [PERF_REG_POWERPC_R4] = "r4", | ||
25 | [PERF_REG_POWERPC_R5] = "r5", | ||
26 | [PERF_REG_POWERPC_R6] = "r6", | ||
27 | [PERF_REG_POWERPC_R7] = "r7", | ||
28 | [PERF_REG_POWERPC_R8] = "r8", | ||
29 | [PERF_REG_POWERPC_R9] = "r9", | ||
30 | [PERF_REG_POWERPC_R10] = "r10", | ||
31 | [PERF_REG_POWERPC_R11] = "r11", | ||
32 | [PERF_REG_POWERPC_R12] = "r12", | ||
33 | [PERF_REG_POWERPC_R13] = "r13", | ||
34 | [PERF_REG_POWERPC_R14] = "r14", | ||
35 | [PERF_REG_POWERPC_R15] = "r15", | ||
36 | [PERF_REG_POWERPC_R16] = "r16", | ||
37 | [PERF_REG_POWERPC_R17] = "r17", | ||
38 | [PERF_REG_POWERPC_R18] = "r18", | ||
39 | [PERF_REG_POWERPC_R19] = "r19", | ||
40 | [PERF_REG_POWERPC_R20] = "r20", | ||
41 | [PERF_REG_POWERPC_R21] = "r21", | ||
42 | [PERF_REG_POWERPC_R22] = "r22", | ||
43 | [PERF_REG_POWERPC_R23] = "r23", | ||
44 | [PERF_REG_POWERPC_R24] = "r24", | ||
45 | [PERF_REG_POWERPC_R25] = "r25", | ||
46 | [PERF_REG_POWERPC_R26] = "r26", | ||
47 | [PERF_REG_POWERPC_R27] = "r27", | ||
48 | [PERF_REG_POWERPC_R28] = "r28", | ||
49 | [PERF_REG_POWERPC_R29] = "r29", | ||
50 | [PERF_REG_POWERPC_R30] = "r30", | ||
51 | [PERF_REG_POWERPC_R31] = "r31", | ||
52 | [PERF_REG_POWERPC_NIP] = "nip", | ||
53 | [PERF_REG_POWERPC_MSR] = "msr", | ||
54 | [PERF_REG_POWERPC_ORIG_R3] = "orig_r3", | ||
55 | [PERF_REG_POWERPC_CTR] = "ctr", | ||
56 | [PERF_REG_POWERPC_LINK] = "link", | ||
57 | [PERF_REG_POWERPC_XER] = "xer", | ||
58 | [PERF_REG_POWERPC_CCR] = "ccr", | ||
59 | [PERF_REG_POWERPC_SOFTE] = "softe", | ||
60 | [PERF_REG_POWERPC_TRAP] = "trap", | ||
61 | [PERF_REG_POWERPC_DAR] = "dar", | ||
62 | [PERF_REG_POWERPC_DSISR] = "dsisr" | ||
63 | }; | ||
64 | |||
65 | static inline const char *perf_reg_name(int id) | ||
66 | { | ||
67 | return reg_names[id]; | ||
68 | } | ||
69 | #endif /* ARCH_PERF_REGS_H */ | ||
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index c8fe2074d217..90ad64b231cd 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build | |||
@@ -1,6 +1,8 @@ | |||
1 | libperf-y += header.o | 1 | libperf-y += header.o |
2 | libperf-y += sym-handling.o | 2 | libperf-y += sym-handling.o |
3 | libperf-y += kvm-stat.o | 3 | libperf-y += kvm-stat.o |
4 | libperf-y += perf_regs.o | ||
4 | 5 | ||
5 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | 6 | libperf-$(CONFIG_DWARF) += dwarf-regs.o |
6 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o | 7 | libperf-$(CONFIG_DWARF) += skip-callchain-idx.o |
8 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o | ||
diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c new file mode 100644 index 000000000000..a3c3e1ce6807 --- /dev/null +++ b/tools/perf/arch/powerpc/util/perf_regs.c | |||
@@ -0,0 +1,49 @@ | |||
1 | #include "../../perf.h" | ||
2 | #include "../../util/perf_regs.h" | ||
3 | |||
4 | const struct sample_reg sample_reg_masks[] = { | ||
5 | SMPL_REG(r0, PERF_REG_POWERPC_R0), | ||
6 | SMPL_REG(r1, PERF_REG_POWERPC_R1), | ||
7 | SMPL_REG(r2, PERF_REG_POWERPC_R2), | ||
8 | SMPL_REG(r3, PERF_REG_POWERPC_R3), | ||
9 | SMPL_REG(r4, PERF_REG_POWERPC_R4), | ||
10 | SMPL_REG(r5, PERF_REG_POWERPC_R5), | ||
11 | SMPL_REG(r6, PERF_REG_POWERPC_R6), | ||
12 | SMPL_REG(r7, PERF_REG_POWERPC_R7), | ||
13 | SMPL_REG(r8, PERF_REG_POWERPC_R8), | ||
14 | SMPL_REG(r9, PERF_REG_POWERPC_R9), | ||
15 | SMPL_REG(r10, PERF_REG_POWERPC_R10), | ||
16 | SMPL_REG(r11, PERF_REG_POWERPC_R11), | ||
17 | SMPL_REG(r12, PERF_REG_POWERPC_R12), | ||
18 | SMPL_REG(r13, PERF_REG_POWERPC_R13), | ||
19 | SMPL_REG(r14, PERF_REG_POWERPC_R14), | ||
20 | SMPL_REG(r15, PERF_REG_POWERPC_R15), | ||
21 | SMPL_REG(r16, PERF_REG_POWERPC_R16), | ||
22 | SMPL_REG(r17, PERF_REG_POWERPC_R17), | ||
23 | SMPL_REG(r18, PERF_REG_POWERPC_R18), | ||
24 | SMPL_REG(r19, PERF_REG_POWERPC_R19), | ||
25 | SMPL_REG(r20, PERF_REG_POWERPC_R20), | ||
26 | SMPL_REG(r21, PERF_REG_POWERPC_R21), | ||
27 | SMPL_REG(r22, PERF_REG_POWERPC_R22), | ||
28 | SMPL_REG(r23, PERF_REG_POWERPC_R23), | ||
29 | SMPL_REG(r24, PERF_REG_POWERPC_R24), | ||
30 | SMPL_REG(r25, PERF_REG_POWERPC_R25), | ||
31 | SMPL_REG(r26, PERF_REG_POWERPC_R26), | ||
32 | SMPL_REG(r27, PERF_REG_POWERPC_R27), | ||
33 | SMPL_REG(r28, PERF_REG_POWERPC_R28), | ||
34 | SMPL_REG(r29, PERF_REG_POWERPC_R29), | ||
35 | SMPL_REG(r30, PERF_REG_POWERPC_R30), | ||
36 | SMPL_REG(r31, PERF_REG_POWERPC_R31), | ||
37 | SMPL_REG(nip, PERF_REG_POWERPC_NIP), | ||
38 | SMPL_REG(msr, PERF_REG_POWERPC_MSR), | ||
39 | SMPL_REG(orig_r3, PERF_REG_POWERPC_ORIG_R3), | ||
40 | SMPL_REG(ctr, PERF_REG_POWERPC_CTR), | ||
41 | SMPL_REG(link, PERF_REG_POWERPC_LINK), | ||
42 | SMPL_REG(xer, PERF_REG_POWERPC_XER), | ||
43 | SMPL_REG(ccr, PERF_REG_POWERPC_CCR), | ||
44 | SMPL_REG(softe, PERF_REG_POWERPC_SOFTE), | ||
45 | SMPL_REG(trap, PERF_REG_POWERPC_TRAP), | ||
46 | SMPL_REG(dar, PERF_REG_POWERPC_DAR), | ||
47 | SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR), | ||
48 | SMPL_REG_END | ||
49 | }; | ||
diff --git a/tools/perf/arch/powerpc/util/unwind-libunwind.c b/tools/perf/arch/powerpc/util/unwind-libunwind.c new file mode 100644 index 000000000000..9e15f92ae49f --- /dev/null +++ b/tools/perf/arch/powerpc/util/unwind-libunwind.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright 2016 Chandan Kumar, 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 | |||
10 | #include <errno.h> | ||
11 | #include <libunwind.h> | ||
12 | #include <asm/perf_regs.h> | ||
13 | #include "../../util/unwind.h" | ||
14 | #include "../../util/debug.h" | ||
15 | |||
16 | int libunwind__arch_reg_id(int regnum) | ||
17 | { | ||
18 | switch (regnum) { | ||
19 | case UNW_PPC64_R0: | ||
20 | return PERF_REG_POWERPC_R0; | ||
21 | case UNW_PPC64_R1: | ||
22 | return PERF_REG_POWERPC_R1; | ||
23 | case UNW_PPC64_R2: | ||
24 | return PERF_REG_POWERPC_R2; | ||
25 | case UNW_PPC64_R3: | ||
26 | return PERF_REG_POWERPC_R3; | ||
27 | case UNW_PPC64_R4: | ||
28 | return PERF_REG_POWERPC_R4; | ||
29 | case UNW_PPC64_R5: | ||
30 | return PERF_REG_POWERPC_R5; | ||
31 | case UNW_PPC64_R6: | ||
32 | return PERF_REG_POWERPC_R6; | ||
33 | case UNW_PPC64_R7: | ||
34 | return PERF_REG_POWERPC_R7; | ||
35 | case UNW_PPC64_R8: | ||
36 | return PERF_REG_POWERPC_R8; | ||
37 | case UNW_PPC64_R9: | ||
38 | return PERF_REG_POWERPC_R9; | ||
39 | case UNW_PPC64_R10: | ||
40 | return PERF_REG_POWERPC_R10; | ||
41 | case UNW_PPC64_R11: | ||
42 | return PERF_REG_POWERPC_R11; | ||
43 | case UNW_PPC64_R12: | ||
44 | return PERF_REG_POWERPC_R12; | ||
45 | case UNW_PPC64_R13: | ||
46 | return PERF_REG_POWERPC_R13; | ||
47 | case UNW_PPC64_R14: | ||
48 | return PERF_REG_POWERPC_R14; | ||
49 | case UNW_PPC64_R15: | ||
50 | return PERF_REG_POWERPC_R15; | ||
51 | case UNW_PPC64_R16: | ||
52 | return PERF_REG_POWERPC_R16; | ||
53 | case UNW_PPC64_R17: | ||
54 | return PERF_REG_POWERPC_R17; | ||
55 | case UNW_PPC64_R18: | ||
56 | return PERF_REG_POWERPC_R18; | ||
57 | case UNW_PPC64_R19: | ||
58 | return PERF_REG_POWERPC_R19; | ||
59 | case UNW_PPC64_R20: | ||
60 | return PERF_REG_POWERPC_R20; | ||
61 | case UNW_PPC64_R21: | ||
62 | return PERF_REG_POWERPC_R21; | ||
63 | case UNW_PPC64_R22: | ||
64 | return PERF_REG_POWERPC_R22; | ||
65 | case UNW_PPC64_R23: | ||
66 | return PERF_REG_POWERPC_R23; | ||
67 | case UNW_PPC64_R24: | ||
68 | return PERF_REG_POWERPC_R24; | ||
69 | case UNW_PPC64_R25: | ||
70 | return PERF_REG_POWERPC_R25; | ||
71 | case UNW_PPC64_R26: | ||
72 | return PERF_REG_POWERPC_R26; | ||
73 | case UNW_PPC64_R27: | ||
74 | return PERF_REG_POWERPC_R27; | ||
75 | case UNW_PPC64_R28: | ||
76 | return PERF_REG_POWERPC_R28; | ||
77 | case UNW_PPC64_R29: | ||
78 | return PERF_REG_POWERPC_R29; | ||
79 | case UNW_PPC64_R30: | ||
80 | return PERF_REG_POWERPC_R30; | ||
81 | case UNW_PPC64_R31: | ||
82 | return PERF_REG_POWERPC_R31; | ||
83 | case UNW_PPC64_LR: | ||
84 | return PERF_REG_POWERPC_LINK; | ||
85 | case UNW_PPC64_CTR: | ||
86 | return PERF_REG_POWERPC_CTR; | ||
87 | case UNW_PPC64_XER: | ||
88 | return PERF_REG_POWERPC_XER; | ||
89 | case UNW_PPC64_NIP: | ||
90 | return PERF_REG_POWERPC_NIP; | ||
91 | default: | ||
92 | pr_err("unwind: invalid reg id %d\n", regnum); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | return -EINVAL; | ||
96 | } | ||
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277286c2..5ad0255f8756 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -23,6 +23,12 @@ $(call detected_var,ARCH) | |||
23 | 23 | ||
24 | NO_PERF_REGS := 1 | 24 | NO_PERF_REGS := 1 |
25 | 25 | ||
26 | # Additional ARCH settings for ppc | ||
27 | ifeq ($(ARCH),powerpc) | ||
28 | NO_PERF_REGS := 0 | ||
29 | LIBUNWIND_LIBS := -lunwind -lunwind-ppc64 | ||
30 | endif | ||
31 | |||
26 | # Additional ARCH settings for x86 | 32 | # Additional ARCH settings for x86 |
27 | ifeq ($(ARCH),x86) | 33 | ifeq ($(ARCH),x86) |
28 | $(call detected,CONFIG_X86) | 34 | $(call detected,CONFIG_X86) |
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 53c2273e8859..ad1cb63139a7 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c | |||
@@ -73,7 +73,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) | |||
73 | } | 73 | } |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Here we need to explicitely preallocate the counts, as if | 76 | * Here we need to explicitly preallocate the counts, as if |
77 | * we use the auto allocation it will allocate just for 1 cpu, | 77 | * we use the auto allocation it will allocate just for 1 cpu, |
78 | * as we start by cpu 0. | 78 | * as we start by cpu 0. |
79 | */ | 79 | */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 02c177d14c8d..5d7037ef7d3b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -828,7 +828,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, | |||
828 | perf_evsel__set_sample_bit(evsel, PERIOD); | 828 | perf_evsel__set_sample_bit(evsel, PERIOD); |
829 | 829 | ||
830 | /* | 830 | /* |
831 | * When the user explicitely disabled time don't force it here. | 831 | * When the user explicitly disabled time don't force it here. |
832 | */ | 832 | */ |
833 | if (opts->sample_time && | 833 | if (opts->sample_time && |
834 | (!perf_missing_features.sample_id_all && | 834 | (!perf_missing_features.sample_id_all && |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 205d27017361..b1772180c820 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -363,7 +363,7 @@ out_err: | |||
363 | } | 363 | } |
364 | 364 | ||
365 | /* | 365 | /* |
366 | * Caller must eventually drop thread->refcnt returned with a successfull | 366 | * Caller must eventually drop thread->refcnt returned with a successful |
367 | * lookup/new thread inserted. | 367 | * lookup/new thread inserted. |
368 | */ | 368 | */ |
369 | static struct thread *____machine__findnew_thread(struct machine *machine, | 369 | static struct thread *____machine__findnew_thread(struct machine *machine, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bcbc983d4b12..c6fd0479f4cd 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -1649,7 +1649,7 @@ static void parse_events_print_error(struct parse_events_error *err, | |||
1649 | 1649 | ||
1650 | buf = _buf; | 1650 | buf = _buf; |
1651 | 1651 | ||
1652 | /* We're cutting from the beggining. */ | 1652 | /* We're cutting from the beginning. */ |
1653 | if (err->idx > max_err_idx) | 1653 | if (err->idx > max_err_idx) |
1654 | cut = err->idx - max_err_idx; | 1654 | cut = err->idx - max_err_idx; |
1655 | 1655 | ||
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 6b8eb13e14e4..c4023f22f287 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c | |||
@@ -12,18 +12,18 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) | |||
12 | int i, idx = 0; | 12 | int i, idx = 0; |
13 | u64 mask = regs->mask; | 13 | u64 mask = regs->mask; |
14 | 14 | ||
15 | if (regs->cache_mask & (1 << id)) | 15 | if (regs->cache_mask & (1ULL << id)) |
16 | goto out; | 16 | goto out; |
17 | 17 | ||
18 | if (!(mask & (1 << id))) | 18 | if (!(mask & (1ULL << id))) |
19 | return -EINVAL; | 19 | return -EINVAL; |
20 | 20 | ||
21 | for (i = 0; i < id; i++) { | 21 | for (i = 0; i < id; i++) { |
22 | if (mask & (1 << i)) | 22 | if (mask & (1ULL << i)) |
23 | idx++; | 23 | idx++; |
24 | } | 24 | } |
25 | 25 | ||
26 | regs->cache_mask |= (1 << id); | 26 | regs->cache_mask |= (1ULL << id); |
27 | regs->cache_regs[id] = regs->regs[idx]; | 27 | regs->cache_regs[id] = regs->regs[idx]; |
28 | 28 | ||
29 | out: | 29 | out: |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 2335b2824d8a..5214974e841a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -557,7 +557,7 @@ static u8 revbyte(u8 b) | |||
557 | 557 | ||
558 | /* | 558 | /* |
559 | * XXX this is hack in attempt to carry flags bitfield | 559 | * XXX this is hack in attempt to carry flags bitfield |
560 | * throught endian village. ABI says: | 560 | * through endian village. ABI says: |
561 | * | 561 | * |
562 | * Bit-fields are allocated from right to left (least to most significant) | 562 | * Bit-fields are allocated from right to left (least to most significant) |
563 | * on little-endian implementations and from left to right (most to least | 563 | * on little-endian implementations and from left to right (most to least |
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index d0e6b857d8d1..546cf4a503b7 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | |||
@@ -91,7 +91,7 @@ osl_get_customized_table(char *pathname, | |||
91 | char *signature, | 91 | char *signature, |
92 | u32 instance, | 92 | u32 instance, |
93 | struct acpi_table_header **table, | 93 | struct acpi_table_header **table, |
94 | acpi_physical_address * address); | 94 | acpi_physical_address *address); |
95 | 95 | ||
96 | static acpi_status osl_list_bios_tables(void); | 96 | static acpi_status osl_list_bios_tables(void); |
97 | 97 | ||
@@ -99,7 +99,7 @@ static acpi_status | |||
99 | osl_get_bios_table(char *signature, | 99 | osl_get_bios_table(char *signature, |
100 | u32 instance, | 100 | u32 instance, |
101 | struct acpi_table_header **table, | 101 | struct acpi_table_header **table, |
102 | acpi_physical_address * address); | 102 | acpi_physical_address *address); |
103 | 103 | ||
104 | static acpi_status osl_get_last_status(acpi_status default_status); | 104 | static acpi_status osl_get_last_status(acpi_status default_status); |
105 | 105 | ||
@@ -187,7 +187,7 @@ static acpi_status osl_get_last_status(acpi_status default_status) | |||
187 | 187 | ||
188 | acpi_status | 188 | acpi_status |
189 | acpi_os_get_table_by_address(acpi_physical_address address, | 189 | acpi_os_get_table_by_address(acpi_physical_address address, |
190 | struct acpi_table_header ** table) | 190 | struct acpi_table_header **table) |
191 | { | 191 | { |
192 | u32 table_length; | 192 | u32 table_length; |
193 | struct acpi_table_header *mapped_table; | 193 | struct acpi_table_header *mapped_table; |
@@ -252,8 +252,8 @@ exit: | |||
252 | acpi_status | 252 | acpi_status |
253 | acpi_os_get_table_by_name(char *signature, | 253 | acpi_os_get_table_by_name(char *signature, |
254 | u32 instance, | 254 | u32 instance, |
255 | struct acpi_table_header ** table, | 255 | struct acpi_table_header **table, |
256 | acpi_physical_address * address) | 256 | acpi_physical_address *address) |
257 | { | 257 | { |
258 | acpi_status status; | 258 | acpi_status status; |
259 | 259 | ||
@@ -380,8 +380,8 @@ static acpi_status osl_add_table_to_list(char *signature, u32 instance) | |||
380 | 380 | ||
381 | acpi_status | 381 | acpi_status |
382 | acpi_os_get_table_by_index(u32 index, | 382 | acpi_os_get_table_by_index(u32 index, |
383 | struct acpi_table_header ** table, | 383 | struct acpi_table_header **table, |
384 | u32 *instance, acpi_physical_address * address) | 384 | u32 *instance, acpi_physical_address *address) |
385 | { | 385 | { |
386 | struct osl_table_info *info; | 386 | struct osl_table_info *info; |
387 | acpi_status status; | 387 | acpi_status status; |
@@ -447,7 +447,7 @@ osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword) | |||
447 | } | 447 | } |
448 | } | 448 | } |
449 | 449 | ||
450 | return ((acpi_physical_address) (address)); | 450 | return ((acpi_physical_address)(address)); |
451 | } | 451 | } |
452 | 452 | ||
453 | /****************************************************************************** | 453 | /****************************************************************************** |
@@ -751,10 +751,10 @@ static acpi_status osl_list_bios_tables(void) | |||
751 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | 751 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { |
752 | if (osl_can_use_xsdt()) { | 752 | if (osl_can_use_xsdt()) { |
753 | table_address = | 753 | table_address = |
754 | (acpi_physical_address) (*ACPI_CAST64(table_data)); | 754 | (acpi_physical_address)(*ACPI_CAST64(table_data)); |
755 | } else { | 755 | } else { |
756 | table_address = | 756 | table_address = |
757 | (acpi_physical_address) (*ACPI_CAST32(table_data)); | 757 | (acpi_physical_address)(*ACPI_CAST32(table_data)); |
758 | } | 758 | } |
759 | 759 | ||
760 | /* Skip NULL entries in RSDT/XSDT */ | 760 | /* Skip NULL entries in RSDT/XSDT */ |
@@ -800,7 +800,7 @@ static acpi_status | |||
800 | osl_get_bios_table(char *signature, | 800 | osl_get_bios_table(char *signature, |
801 | u32 instance, | 801 | u32 instance, |
802 | struct acpi_table_header **table, | 802 | struct acpi_table_header **table, |
803 | acpi_physical_address * address) | 803 | acpi_physical_address *address) |
804 | { | 804 | { |
805 | struct acpi_table_header *local_table = NULL; | 805 | struct acpi_table_header *local_table = NULL; |
806 | struct acpi_table_header *mapped_table = NULL; | 806 | struct acpi_table_header *mapped_table = NULL; |
@@ -833,38 +833,37 @@ osl_get_bios_table(char *signature, | |||
833 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && | 833 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && |
834 | gbl_fadt->Xdsdt) { | 834 | gbl_fadt->Xdsdt) { |
835 | table_address = | 835 | table_address = |
836 | (acpi_physical_address) gbl_fadt->Xdsdt; | 836 | (acpi_physical_address)gbl_fadt->Xdsdt; |
837 | } else | 837 | } else |
838 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) | 838 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) |
839 | && gbl_fadt->dsdt) { | 839 | && gbl_fadt->dsdt) { |
840 | table_address = | 840 | table_address = |
841 | (acpi_physical_address) gbl_fadt->dsdt; | 841 | (acpi_physical_address)gbl_fadt->dsdt; |
842 | } | 842 | } |
843 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | 843 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { |
844 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && | 844 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && |
845 | gbl_fadt->Xfacs) { | 845 | gbl_fadt->Xfacs) { |
846 | table_address = | 846 | table_address = |
847 | (acpi_physical_address) gbl_fadt->Xfacs; | 847 | (acpi_physical_address)gbl_fadt->Xfacs; |
848 | } else | 848 | } else |
849 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) | 849 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) |
850 | && gbl_fadt->facs) { | 850 | && gbl_fadt->facs) { |
851 | table_address = | 851 | table_address = |
852 | (acpi_physical_address) gbl_fadt->facs; | 852 | (acpi_physical_address)gbl_fadt->facs; |
853 | } | 853 | } |
854 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { | 854 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { |
855 | if (!gbl_revision) { | 855 | if (!gbl_revision) { |
856 | return (AE_BAD_SIGNATURE); | 856 | return (AE_BAD_SIGNATURE); |
857 | } | 857 | } |
858 | table_address = | 858 | table_address = |
859 | (acpi_physical_address) gbl_rsdp. | 859 | (acpi_physical_address)gbl_rsdp. |
860 | xsdt_physical_address; | 860 | xsdt_physical_address; |
861 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { | 861 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { |
862 | table_address = | 862 | table_address = |
863 | (acpi_physical_address) gbl_rsdp. | 863 | (acpi_physical_address)gbl_rsdp. |
864 | rsdt_physical_address; | 864 | rsdt_physical_address; |
865 | } else { | 865 | } else { |
866 | table_address = | 866 | table_address = (acpi_physical_address)gbl_rsdp_address; |
867 | (acpi_physical_address) gbl_rsdp_address; | ||
868 | signature = ACPI_SIG_RSDP; | 867 | signature = ACPI_SIG_RSDP; |
869 | } | 868 | } |
870 | 869 | ||
@@ -904,12 +903,12 @@ osl_get_bios_table(char *signature, | |||
904 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | 903 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { |
905 | if (osl_can_use_xsdt()) { | 904 | if (osl_can_use_xsdt()) { |
906 | table_address = | 905 | table_address = |
907 | (acpi_physical_address) (*ACPI_CAST64 | 906 | (acpi_physical_address)(*ACPI_CAST64 |
908 | (table_data)); | 907 | (table_data)); |
909 | } else { | 908 | } else { |
910 | table_address = | 909 | table_address = |
911 | (acpi_physical_address) (*ACPI_CAST32 | 910 | (acpi_physical_address)(*ACPI_CAST32 |
912 | (table_data)); | 911 | (table_data)); |
913 | } | 912 | } |
914 | 913 | ||
915 | /* Skip NULL entries in RSDT/XSDT */ | 914 | /* Skip NULL entries in RSDT/XSDT */ |
@@ -1301,7 +1300,7 @@ osl_get_customized_table(char *pathname, | |||
1301 | char *signature, | 1300 | char *signature, |
1302 | u32 instance, | 1301 | u32 instance, |
1303 | struct acpi_table_header **table, | 1302 | struct acpi_table_header **table, |
1304 | acpi_physical_address * address) | 1303 | acpi_physical_address *address) |
1305 | { | 1304 | { |
1306 | void *table_dir; | 1305 | void *table_dir; |
1307 | u32 current_instance = 0; | 1306 | u32 current_instance = 0; |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c index 3818fd07e50f..cbfbce18783d 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixmap.c +++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c | |||
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("osunixmap") | |||
54 | #ifndef O_BINARY | 54 | #ifndef O_BINARY |
55 | #define O_BINARY 0 | 55 | #define O_BINARY 0 |
56 | #endif | 56 | #endif |
57 | #if defined(_dragon_fly) || defined(_free_BSD) | 57 | #if defined(_dragon_fly) || defined(_free_BSD) || defined(_QNX) |
58 | #define MMAP_FLAGS MAP_SHARED | 58 | #define MMAP_FLAGS MAP_SHARED |
59 | #else | 59 | #else |
60 | #define MMAP_FLAGS MAP_PRIVATE | 60 | #define MMAP_FLAGS MAP_PRIVATE |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 08cb8b2035f2..88aa66ef4ad5 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c | |||
@@ -246,8 +246,8 @@ acpi_physical_address acpi_os_get_root_pointer(void) | |||
246 | *****************************************************************************/ | 246 | *****************************************************************************/ |
247 | 247 | ||
248 | acpi_status | 248 | acpi_status |
249 | acpi_os_predefined_override(const struct acpi_predefined_names * init_val, | 249 | acpi_os_predefined_override(const struct acpi_predefined_names *init_val, |
250 | acpi_string * new_val) | 250 | acpi_string *new_val) |
251 | { | 251 | { |
252 | 252 | ||
253 | if (!init_val || !new_val) { | 253 | if (!init_val || !new_val) { |
@@ -274,8 +274,8 @@ acpi_os_predefined_override(const struct acpi_predefined_names * init_val, | |||
274 | *****************************************************************************/ | 274 | *****************************************************************************/ |
275 | 275 | ||
276 | acpi_status | 276 | acpi_status |
277 | acpi_os_table_override(struct acpi_table_header * existing_table, | 277 | acpi_os_table_override(struct acpi_table_header *existing_table, |
278 | struct acpi_table_header ** new_table) | 278 | struct acpi_table_header **new_table) |
279 | { | 279 | { |
280 | 280 | ||
281 | if (!existing_table || !new_table) { | 281 | if (!existing_table || !new_table) { |
@@ -311,8 +311,8 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | |||
311 | *****************************************************************************/ | 311 | *****************************************************************************/ |
312 | 312 | ||
313 | acpi_status | 313 | acpi_status |
314 | acpi_os_physical_table_override(struct acpi_table_header * existing_table, | 314 | acpi_os_physical_table_override(struct acpi_table_header *existing_table, |
315 | acpi_physical_address * new_address, | 315 | acpi_physical_address *new_address, |
316 | u32 *new_table_length) | 316 | u32 *new_table_length) |
317 | { | 317 | { |
318 | 318 | ||
@@ -506,7 +506,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) | |||
506 | void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) | 506 | void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) |
507 | { | 507 | { |
508 | 508 | ||
509 | return (ACPI_TO_POINTER((acpi_size) where)); | 509 | return (ACPI_TO_POINTER((acpi_size)where)); |
510 | } | 510 | } |
511 | 511 | ||
512 | /****************************************************************************** | 512 | /****************************************************************************** |
@@ -603,9 +603,9 @@ void acpi_os_free(void *mem) | |||
603 | 603 | ||
604 | acpi_status | 604 | acpi_status |
605 | acpi_os_create_semaphore(u32 max_units, | 605 | acpi_os_create_semaphore(u32 max_units, |
606 | u32 initial_units, acpi_handle * out_handle) | 606 | u32 initial_units, acpi_handle *out_handle) |
607 | { | 607 | { |
608 | *out_handle = (acpi_handle) 1; | 608 | *out_handle = (acpi_handle)1; |
609 | return (AE_OK); | 609 | return (AE_OK); |
610 | } | 610 | } |
611 | 611 | ||
@@ -640,7 +640,7 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) | |||
640 | 640 | ||
641 | acpi_status | 641 | acpi_status |
642 | acpi_os_create_semaphore(u32 max_units, | 642 | acpi_os_create_semaphore(u32 max_units, |
643 | u32 initial_units, acpi_handle * out_handle) | 643 | u32 initial_units, acpi_handle *out_handle) |
644 | { | 644 | { |
645 | sem_t *sem; | 645 | sem_t *sem; |
646 | 646 | ||
@@ -672,7 +672,7 @@ acpi_os_create_semaphore(u32 max_units, | |||
672 | } | 672 | } |
673 | #endif | 673 | #endif |
674 | 674 | ||
675 | *out_handle = (acpi_handle) sem; | 675 | *out_handle = (acpi_handle)sem; |
676 | return (AE_OK); | 676 | return (AE_OK); |
677 | } | 677 | } |
678 | 678 | ||
@@ -1035,7 +1035,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, | |||
1035 | *****************************************************************************/ | 1035 | *****************************************************************************/ |
1036 | 1036 | ||
1037 | acpi_status | 1037 | acpi_status |
1038 | acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, | 1038 | acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, |
1039 | u32 pci_register, u64 value, u32 width) | 1039 | u32 pci_register, u64 value, u32 width) |
1040 | { | 1040 | { |
1041 | 1041 | ||
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c index d070fccdba6d..a88ac45b7756 100644 --- a/tools/power/acpi/tools/acpidbg/acpidbg.c +++ b/tools/power/acpi/tools/acpidbg/acpidbg.c | |||
@@ -375,7 +375,7 @@ void usage(FILE *file, char *progname) | |||
375 | 375 | ||
376 | int main(int argc, char **argv) | 376 | int main(int argc, char **argv) |
377 | { | 377 | { |
378 | int fd = 0; | 378 | int fd = -1; |
379 | int ch; | 379 | int ch; |
380 | int len; | 380 | int len; |
381 | int ret = EXIT_SUCCESS; | 381 | int ret = EXIT_SUCCESS; |
@@ -430,7 +430,7 @@ int main(int argc, char **argv) | |||
430 | acpi_aml_loop(fd); | 430 | acpi_aml_loop(fd); |
431 | 431 | ||
432 | exit: | 432 | exit: |
433 | if (fd < 0) | 433 | if (fd >= 0) |
434 | close(fd); | 434 | close(fd); |
435 | if (acpi_aml_batch_cmd) | 435 | if (acpi_aml_batch_cmd) |
436 | free(acpi_aml_batch_cmd); | 436 | free(acpi_aml_batch_cmd); |
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile index 8d761576e91b..2942cdced2ad 100644 --- a/tools/power/acpi/tools/acpidump/Makefile +++ b/tools/power/acpi/tools/acpidump/Makefile | |||
@@ -31,6 +31,7 @@ TOOL_OBJS = \ | |||
31 | osunixxf.o\ | 31 | osunixxf.o\ |
32 | tbprint.o\ | 32 | tbprint.o\ |
33 | tbxfroot.o\ | 33 | tbxfroot.o\ |
34 | utascii.o\ | ||
34 | utbuffer.o\ | 35 | utbuffer.o\ |
35 | utdebug.o\ | 36 | utdebug.o\ |
36 | utexcep.o\ | 37 | utexcep.o\ |
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index da44458d3b6c..fb8f1d9e3b1b 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c | |||
@@ -68,7 +68,7 @@ u8 ap_is_valid_header(struct acpi_table_header *table) | |||
68 | 68 | ||
69 | /* Make sure signature is all ASCII and a valid ACPI name */ | 69 | /* Make sure signature is all ASCII and a valid ACPI name */ |
70 | 70 | ||
71 | if (!acpi_ut_valid_acpi_name(table->signature)) { | 71 | if (!acpi_ut_valid_nameseg(table->signature)) { |
72 | acpi_log_error("Table signature (0x%8.8X) is invalid\n", | 72 | acpi_log_error("Table signature (0x%8.8X) is invalid\n", |
73 | *(u32 *)table->signature); | 73 | *(u32 *)table->signature); |
74 | return (FALSE); | 74 | return (FALSE); |
@@ -286,14 +286,15 @@ int ap_dump_table_by_address(char *ascii_address) | |||
286 | 286 | ||
287 | /* Convert argument to an integer physical address */ | 287 | /* Convert argument to an integer physical address */ |
288 | 288 | ||
289 | status = acpi_ut_strtoul64(ascii_address, 0, &long_address); | 289 | status = acpi_ut_strtoul64(ascii_address, ACPI_ANY_BASE, |
290 | ACPI_MAX64_BYTE_WIDTH, &long_address); | ||
290 | if (ACPI_FAILURE(status)) { | 291 | if (ACPI_FAILURE(status)) { |
291 | acpi_log_error("%s: Could not convert to a physical address\n", | 292 | acpi_log_error("%s: Could not convert to a physical address\n", |
292 | ascii_address); | 293 | ascii_address); |
293 | return (-1); | 294 | return (-1); |
294 | } | 295 | } |
295 | 296 | ||
296 | address = (acpi_physical_address) long_address; | 297 | address = (acpi_physical_address)long_address; |
297 | status = acpi_os_get_table_by_address(address, &table); | 298 | status = acpi_os_get_table_by_address(address, &table); |
298 | if (ACPI_FAILURE(status)) { | 299 | if (ACPI_FAILURE(status)) { |
299 | acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n", | 300 | acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n", |
@@ -406,6 +407,12 @@ int ap_dump_table_from_file(char *pathname) | |||
406 | return (-1); | 407 | return (-1); |
407 | } | 408 | } |
408 | 409 | ||
410 | if (!acpi_ut_valid_nameseg(table->signature)) { | ||
411 | acpi_log_error | ||
412 | ("No valid ACPI signature was found in input file %s\n", | ||
413 | pathname); | ||
414 | } | ||
415 | |||
409 | /* File must be at least as long as the table length */ | 416 | /* File must be at least as long as the table length */ |
410 | 417 | ||
411 | if (table->length > file_size) { | 418 | if (table->length > file_size) { |
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index c3c09152fac6..7692e6b887e1 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c | |||
@@ -209,7 +209,8 @@ static int ap_do_options(int argc, char **argv) | |||
209 | case 'r': /* Dump tables from specified RSDP */ | 209 | case 'r': /* Dump tables from specified RSDP */ |
210 | 210 | ||
211 | status = | 211 | status = |
212 | acpi_ut_strtoul64(acpi_gbl_optarg, 0, | 212 | acpi_ut_strtoul64(acpi_gbl_optarg, ACPI_ANY_BASE, |
213 | ACPI_MAX64_BYTE_WIDTH, | ||
213 | &gbl_rsdp_base); | 214 | &gbl_rsdp_base); |
214 | if (ACPI_FAILURE(status)) { | 215 | if (ACPI_FAILURE(status)) { |
215 | acpi_log_error | 216 | acpi_log_error |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 0adaf0c7c03a..8358863259c5 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -63,7 +63,7 @@ DESTDIR ?= | |||
63 | # and _should_ modify the PACKAGE_BUGREPORT definition | 63 | # and _should_ modify the PACKAGE_BUGREPORT definition |
64 | 64 | ||
65 | VERSION= $(shell ./utils/version-gen.sh) | 65 | VERSION= $(shell ./utils/version-gen.sh) |
66 | LIB_MAJ= 0.0.0 | 66 | LIB_MAJ= 0.0.1 |
67 | LIB_MIN= 0 | 67 | LIB_MIN= 0 |
68 | 68 | ||
69 | PACKAGE = cpupower | 69 | PACKAGE = cpupower |
@@ -129,7 +129,7 @@ WARNINGS += -Wshadow | |||
129 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ | 129 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ |
130 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE | 130 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE |
131 | 131 | ||
132 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ | 132 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \ |
133 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ | 133 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ |
134 | utils/helpers/pci.o utils/helpers/bitmask.o \ | 134 | utils/helpers/pci.o utils/helpers/bitmask.o \ |
135 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ | 135 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ |
@@ -148,9 +148,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ | |||
148 | utils/helpers/bitmask.h \ | 148 | utils/helpers/bitmask.h \ |
149 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def | 149 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def |
150 | 150 | ||
151 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h | 151 | LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h |
152 | LIB_SRC = lib/cpufreq.c lib/sysfs.c | 152 | LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c |
153 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o | 153 | LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o |
154 | LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) | 154 | LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) |
155 | 155 | ||
156 | CFLAGS += -pipe | 156 | CFLAGS += -pipe |
@@ -280,6 +280,7 @@ install-lib: | |||
280 | $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ | 280 | $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ |
281 | $(INSTALL) -d $(DESTDIR)${includedir} | 281 | $(INSTALL) -d $(DESTDIR)${includedir} |
282 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h | 282 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h |
283 | $(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h | ||
283 | 284 | ||
284 | install-tools: | 285 | install-tools: |
285 | $(INSTALL) -d $(DESTDIR)${bindir} | 286 | $(INSTALL) -d $(DESTDIR)${bindir} |
@@ -315,6 +316,7 @@ endif | |||
315 | uninstall: | 316 | uninstall: |
316 | - rm -f $(DESTDIR)${libdir}/libcpupower.* | 317 | - rm -f $(DESTDIR)${libdir}/libcpupower.* |
317 | - rm -f $(DESTDIR)${includedir}/cpufreq.h | 318 | - rm -f $(DESTDIR)${includedir}/cpufreq.h |
319 | - rm -f $(DESTDIR)${includedir}/cpuidle.h | ||
318 | - rm -f $(DESTDIR)${bindir}/utils/cpupower | 320 | - rm -f $(DESTDIR)${bindir}/utils/cpupower |
319 | - rm -f $(DESTDIR)${mandir}/man1/cpupower.1 | 321 | - rm -f $(DESTDIR)${mandir}/man1/cpupower.1 |
320 | - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 | 322 | - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 |
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile index d0f879b223fc..3e59f1aa3947 100644 --- a/tools/power/cpupower/bench/Makefile +++ b/tools/power/cpupower/bench/Makefile | |||
@@ -22,7 +22,7 @@ $(OUTPUT)%.o : %.c | |||
22 | 22 | ||
23 | $(OUTPUT)cpufreq-bench: $(OBJS) | 23 | $(OUTPUT)cpufreq-bench: $(OBJS) |
24 | $(ECHO) " CC " $@ | 24 | $(ECHO) " CC " $@ |
25 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) | 25 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) |
26 | 26 | ||
27 | all: $(OUTPUT)cpufreq-bench | 27 | all: $(OUTPUT)cpufreq-bench |
28 | 28 | ||
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH index 8093ec738170..97727aed61cc 100644 --- a/tools/power/cpupower/bench/README-BENCH +++ b/tools/power/cpupower/bench/README-BENCH | |||
@@ -113,7 +113,7 @@ cpufreq-bench Command Usage | |||
113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 | 113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 |
114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT | 114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT |
115 | -g, --governor=<governor> cpufreq governor to test | 115 | -g, --governor=<governor> cpufreq governor to test |
116 | -n, --cycles=<int> load/sleep cycles to get an avarage value to compare | 116 | -n, --cycles=<int> load/sleep cycles to get an average value to compare |
117 | -r, --rounds<int> load/sleep rounds | 117 | -r, --rounds<int> load/sleep rounds |
118 | -f, --file=<configfile> config file to use | 118 | -f, --file=<configfile> config file to use |
119 | -o, --output=<dir> output dir, must exist | 119 | -o, --output=<dir> output dir, must exist |
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c index 81b1c48607d9..429d51ab8031 100644 --- a/tools/power/cpupower/bench/benchmark.c +++ b/tools/power/cpupower/bench/benchmark.c | |||
@@ -130,7 +130,7 @@ void start_benchmark(struct config *config) | |||
130 | _round, load_time, sleep_time); | 130 | _round, load_time, sleep_time); |
131 | 131 | ||
132 | if (config->verbose) | 132 | if (config->verbose) |
133 | printf("avarage: %lius, rps:%li\n", | 133 | printf("average: %lius, rps:%li\n", |
134 | load_time / calculations, | 134 | load_time / calculations, |
135 | 1000000 * calculations / load_time); | 135 | 1000000 * calculations / load_time); |
136 | 136 | ||
@@ -177,7 +177,7 @@ void start_benchmark(struct config *config) | |||
177 | 177 | ||
178 | progress_time += sleep_time + load_time; | 178 | progress_time += sleep_time + load_time; |
179 | 179 | ||
180 | /* compare the avarage sleep/load cycles */ | 180 | /* compare the average sleep/load cycles */ |
181 | fprintf(config->output, "%li ", | 181 | fprintf(config->output, "%li ", |
182 | powersave_time / config->cycles); | 182 | powersave_time / config->cycles); |
183 | fprintf(config->output, "%.3f\n", | 183 | fprintf(config->output, "%.3f\n", |
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c index f503fb53824e..9b65f052081f 100644 --- a/tools/power/cpupower/bench/parse.c +++ b/tools/power/cpupower/bench/parse.c | |||
@@ -65,7 +65,7 @@ FILE *prepare_output(const char *dirname) | |||
65 | { | 65 | { |
66 | FILE *output = NULL; | 66 | FILE *output = NULL; |
67 | int len; | 67 | int len; |
68 | char *filename; | 68 | char *filename, *filename_tmp; |
69 | struct utsname sysdata; | 69 | struct utsname sysdata; |
70 | DIR *dir; | 70 | DIR *dir; |
71 | 71 | ||
@@ -81,16 +81,22 @@ FILE *prepare_output(const char *dirname) | |||
81 | 81 | ||
82 | len = strlen(dirname) + 30; | 82 | len = strlen(dirname) + 30; |
83 | filename = malloc(sizeof(char) * len); | 83 | filename = malloc(sizeof(char) * len); |
84 | if (!filename) { | ||
85 | perror("malloc"); | ||
86 | goto out_dir; | ||
87 | } | ||
84 | 88 | ||
85 | if (uname(&sysdata) == 0) { | 89 | if (uname(&sysdata) == 0) { |
86 | len += strlen(sysdata.nodename) + strlen(sysdata.release); | 90 | len += strlen(sysdata.nodename) + strlen(sysdata.release); |
87 | filename = realloc(filename, sizeof(char) * len); | 91 | filename_tmp = realloc(filename, sizeof(*filename) * len); |
88 | 92 | ||
89 | if (filename == NULL) { | 93 | if (filename_tmp == NULL) { |
94 | free(filename); | ||
90 | perror("realloc"); | 95 | perror("realloc"); |
91 | return NULL; | 96 | goto out_dir; |
92 | } | 97 | } |
93 | 98 | ||
99 | filename = filename_tmp; | ||
94 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", | 100 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", |
95 | dirname, sysdata.nodename, sysdata.release, time(NULL)); | 101 | dirname, sysdata.nodename, sysdata.release, time(NULL)); |
96 | } else { | 102 | } else { |
@@ -104,12 +110,16 @@ FILE *prepare_output(const char *dirname) | |||
104 | if (output == NULL) { | 110 | if (output == NULL) { |
105 | perror("fopen"); | 111 | perror("fopen"); |
106 | fprintf(stderr, "error: unable to open logfile\n"); | 112 | fprintf(stderr, "error: unable to open logfile\n"); |
113 | goto out; | ||
107 | } | 114 | } |
108 | 115 | ||
109 | fprintf(stdout, "Logfile: %s\n", filename); | 116 | fprintf(stdout, "Logfile: %s\n", filename); |
110 | 117 | ||
111 | free(filename); | ||
112 | fprintf(output, "#round load sleep performance powersave percentage\n"); | 118 | fprintf(output, "#round load sleep performance powersave percentage\n"); |
119 | out: | ||
120 | free(filename); | ||
121 | out_dir: | ||
122 | closedir(dir); | ||
113 | return output; | 123 | return output; |
114 | } | 124 | } |
115 | 125 | ||
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c index f01e3f4be84c..c25a74ae51ba 100644 --- a/tools/power/cpupower/bench/system.c +++ b/tools/power/cpupower/bench/system.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <sched.h> | 26 | #include <sched.h> |
27 | 27 | ||
28 | #include <cpufreq.h> | 28 | #include <cpufreq.h> |
29 | #include <cpupower.h> | ||
29 | 30 | ||
30 | #include "config.h" | 31 | #include "config.h" |
31 | #include "system.h" | 32 | #include "system.h" |
@@ -60,7 +61,7 @@ int set_cpufreq_governor(char *governor, unsigned int cpu) | |||
60 | 61 | ||
61 | dprintf("set %s as cpufreq governor\n", governor); | 62 | dprintf("set %s as cpufreq governor\n", governor); |
62 | 63 | ||
63 | if (cpufreq_cpu_exists(cpu) != 0) { | 64 | if (cpupower_is_cpu_online(cpu) != 0) { |
64 | perror("cpufreq_cpu_exists"); | 65 | perror("cpufreq_cpu_exists"); |
65 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); | 66 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); |
66 | return -1; | 67 | return -1; |
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c index d961101d1cea..1b993fe1ce23 100644 --- a/tools/power/cpupower/lib/cpufreq.c +++ b/tools/power/cpupower/lib/cpufreq.c | |||
@@ -9,28 +9,190 @@ | |||
9 | #include <errno.h> | 9 | #include <errno.h> |
10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
12 | 16 | ||
13 | #include "cpufreq.h" | 17 | #include "cpufreq.h" |
14 | #include "sysfs.h" | 18 | #include "cpupower_intern.h" |
15 | 19 | ||
16 | int cpufreq_cpu_exists(unsigned int cpu) | 20 | /* CPUFREQ sysfs access **************************************************/ |
21 | |||
22 | /* helper function to read file from /sys into given buffer */ | ||
23 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
24 | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | ||
25 | char *buf, size_t buflen) | ||
17 | { | 26 | { |
18 | return sysfs_cpu_exists(cpu); | 27 | char path[SYSFS_PATH_MAX]; |
28 | |||
29 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
30 | cpu, fname); | ||
31 | return sysfs_read_file(path, buf, buflen); | ||
19 | } | 32 | } |
20 | 33 | ||
34 | /* helper function to write a new value to a /sys file */ | ||
35 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
36 | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | ||
37 | const char *fname, | ||
38 | const char *value, size_t len) | ||
39 | { | ||
40 | char path[SYSFS_PATH_MAX]; | ||
41 | int fd; | ||
42 | ssize_t numwrite; | ||
43 | |||
44 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
45 | cpu, fname); | ||
46 | |||
47 | fd = open(path, O_WRONLY); | ||
48 | if (fd == -1) | ||
49 | return 0; | ||
50 | |||
51 | numwrite = write(fd, value, len); | ||
52 | if (numwrite < 1) { | ||
53 | close(fd); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | close(fd); | ||
58 | |||
59 | return (unsigned int) numwrite; | ||
60 | } | ||
61 | |||
62 | /* read access to files which contain one numeric value */ | ||
63 | |||
64 | enum cpufreq_value { | ||
65 | CPUINFO_CUR_FREQ, | ||
66 | CPUINFO_MIN_FREQ, | ||
67 | CPUINFO_MAX_FREQ, | ||
68 | CPUINFO_LATENCY, | ||
69 | SCALING_CUR_FREQ, | ||
70 | SCALING_MIN_FREQ, | ||
71 | SCALING_MAX_FREQ, | ||
72 | STATS_NUM_TRANSITIONS, | ||
73 | MAX_CPUFREQ_VALUE_READ_FILES | ||
74 | }; | ||
75 | |||
76 | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | ||
77 | [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | ||
78 | [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | ||
79 | [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | ||
80 | [CPUINFO_LATENCY] = "cpuinfo_transition_latency", | ||
81 | [SCALING_CUR_FREQ] = "scaling_cur_freq", | ||
82 | [SCALING_MIN_FREQ] = "scaling_min_freq", | ||
83 | [SCALING_MAX_FREQ] = "scaling_max_freq", | ||
84 | [STATS_NUM_TRANSITIONS] = "stats/total_trans" | ||
85 | }; | ||
86 | |||
87 | |||
88 | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | ||
89 | enum cpufreq_value which) | ||
90 | { | ||
91 | unsigned long value; | ||
92 | unsigned int len; | ||
93 | char linebuf[MAX_LINE_LEN]; | ||
94 | char *endp; | ||
95 | |||
96 | if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | ||
97 | return 0; | ||
98 | |||
99 | len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | ||
100 | linebuf, sizeof(linebuf)); | ||
101 | |||
102 | if (len == 0) | ||
103 | return 0; | ||
104 | |||
105 | value = strtoul(linebuf, &endp, 0); | ||
106 | |||
107 | if (endp == linebuf || errno == ERANGE) | ||
108 | return 0; | ||
109 | |||
110 | return value; | ||
111 | } | ||
112 | |||
113 | /* read access to files which contain one string */ | ||
114 | |||
115 | enum cpufreq_string { | ||
116 | SCALING_DRIVER, | ||
117 | SCALING_GOVERNOR, | ||
118 | MAX_CPUFREQ_STRING_FILES | ||
119 | }; | ||
120 | |||
121 | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | ||
122 | [SCALING_DRIVER] = "scaling_driver", | ||
123 | [SCALING_GOVERNOR] = "scaling_governor", | ||
124 | }; | ||
125 | |||
126 | |||
127 | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | ||
128 | enum cpufreq_string which) | ||
129 | { | ||
130 | char linebuf[MAX_LINE_LEN]; | ||
131 | char *result; | ||
132 | unsigned int len; | ||
133 | |||
134 | if (which >= MAX_CPUFREQ_STRING_FILES) | ||
135 | return NULL; | ||
136 | |||
137 | len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | ||
138 | linebuf, sizeof(linebuf)); | ||
139 | if (len == 0) | ||
140 | return NULL; | ||
141 | |||
142 | result = strdup(linebuf); | ||
143 | if (result == NULL) | ||
144 | return NULL; | ||
145 | |||
146 | if (result[strlen(result) - 1] == '\n') | ||
147 | result[strlen(result) - 1] = '\0'; | ||
148 | |||
149 | return result; | ||
150 | } | ||
151 | |||
152 | /* write access */ | ||
153 | |||
154 | enum cpufreq_write { | ||
155 | WRITE_SCALING_MIN_FREQ, | ||
156 | WRITE_SCALING_MAX_FREQ, | ||
157 | WRITE_SCALING_GOVERNOR, | ||
158 | WRITE_SCALING_SET_SPEED, | ||
159 | MAX_CPUFREQ_WRITE_FILES | ||
160 | }; | ||
161 | |||
162 | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | ||
163 | [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | ||
164 | [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | ||
165 | [WRITE_SCALING_GOVERNOR] = "scaling_governor", | ||
166 | [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | ||
167 | }; | ||
168 | |||
169 | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | ||
170 | enum cpufreq_write which, | ||
171 | const char *new_value, size_t len) | ||
172 | { | ||
173 | if (which >= MAX_CPUFREQ_WRITE_FILES) | ||
174 | return 0; | ||
175 | |||
176 | if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | ||
177 | new_value, len) != len) | ||
178 | return -ENODEV; | ||
179 | |||
180 | return 0; | ||
181 | }; | ||
182 | |||
21 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu) | 183 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu) |
22 | { | 184 | { |
23 | return sysfs_get_freq_kernel(cpu); | 185 | return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); |
24 | } | 186 | } |
25 | 187 | ||
26 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu) | 188 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu) |
27 | { | 189 | { |
28 | return sysfs_get_freq_hardware(cpu); | 190 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); |
29 | } | 191 | } |
30 | 192 | ||
31 | unsigned long cpufreq_get_transition_latency(unsigned int cpu) | 193 | unsigned long cpufreq_get_transition_latency(unsigned int cpu) |
32 | { | 194 | { |
33 | return sysfs_get_freq_transition_latency(cpu); | 195 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); |
34 | } | 196 | } |
35 | 197 | ||
36 | int cpufreq_get_hardware_limits(unsigned int cpu, | 198 | int cpufreq_get_hardware_limits(unsigned int cpu, |
@@ -39,12 +201,21 @@ int cpufreq_get_hardware_limits(unsigned int cpu, | |||
39 | { | 201 | { |
40 | if ((!min) || (!max)) | 202 | if ((!min) || (!max)) |
41 | return -EINVAL; | 203 | return -EINVAL; |
42 | return sysfs_get_freq_hardware_limits(cpu, min, max); | 204 | |
205 | *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | ||
206 | if (!*min) | ||
207 | return -ENODEV; | ||
208 | |||
209 | *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | ||
210 | if (!*max) | ||
211 | return -ENODEV; | ||
212 | |||
213 | return 0; | ||
43 | } | 214 | } |
44 | 215 | ||
45 | char *cpufreq_get_driver(unsigned int cpu) | 216 | char *cpufreq_get_driver(unsigned int cpu) |
46 | { | 217 | { |
47 | return sysfs_get_freq_driver(cpu); | 218 | return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); |
48 | } | 219 | } |
49 | 220 | ||
50 | void cpufreq_put_driver(char *ptr) | 221 | void cpufreq_put_driver(char *ptr) |
@@ -56,7 +227,26 @@ void cpufreq_put_driver(char *ptr) | |||
56 | 227 | ||
57 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) | 228 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) |
58 | { | 229 | { |
59 | return sysfs_get_freq_policy(cpu); | 230 | struct cpufreq_policy *policy; |
231 | |||
232 | policy = malloc(sizeof(struct cpufreq_policy)); | ||
233 | if (!policy) | ||
234 | return NULL; | ||
235 | |||
236 | policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | ||
237 | if (!policy->governor) { | ||
238 | free(policy); | ||
239 | return NULL; | ||
240 | } | ||
241 | policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
242 | policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | ||
243 | if ((!policy->min) || (!policy->max)) { | ||
244 | free(policy->governor); | ||
245 | free(policy); | ||
246 | return NULL; | ||
247 | } | ||
248 | |||
249 | return policy; | ||
60 | } | 250 | } |
61 | 251 | ||
62 | void cpufreq_put_policy(struct cpufreq_policy *policy) | 252 | void cpufreq_put_policy(struct cpufreq_policy *policy) |
@@ -72,7 +262,57 @@ void cpufreq_put_policy(struct cpufreq_policy *policy) | |||
72 | struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned | 262 | struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned |
73 | int cpu) | 263 | int cpu) |
74 | { | 264 | { |
75 | return sysfs_get_freq_available_governors(cpu); | 265 | struct cpufreq_available_governors *first = NULL; |
266 | struct cpufreq_available_governors *current = NULL; | ||
267 | char linebuf[MAX_LINE_LEN]; | ||
268 | unsigned int pos, i; | ||
269 | unsigned int len; | ||
270 | |||
271 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | ||
272 | linebuf, sizeof(linebuf)); | ||
273 | if (len == 0) | ||
274 | return NULL; | ||
275 | |||
276 | pos = 0; | ||
277 | for (i = 0; i < len; i++) { | ||
278 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
279 | if (i - pos < 2) | ||
280 | continue; | ||
281 | if (current) { | ||
282 | current->next = malloc(sizeof(*current)); | ||
283 | if (!current->next) | ||
284 | goto error_out; | ||
285 | current = current->next; | ||
286 | } else { | ||
287 | first = malloc(sizeof(*first)); | ||
288 | if (!first) | ||
289 | goto error_out; | ||
290 | current = first; | ||
291 | } | ||
292 | current->first = first; | ||
293 | current->next = NULL; | ||
294 | |||
295 | current->governor = malloc(i - pos + 1); | ||
296 | if (!current->governor) | ||
297 | goto error_out; | ||
298 | |||
299 | memcpy(current->governor, linebuf + pos, i - pos); | ||
300 | current->governor[i - pos] = '\0'; | ||
301 | pos = i + 1; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | return first; | ||
306 | |||
307 | error_out: | ||
308 | while (first) { | ||
309 | current = first->next; | ||
310 | if (first->governor) | ||
311 | free(first->governor); | ||
312 | free(first); | ||
313 | first = current; | ||
314 | } | ||
315 | return NULL; | ||
76 | } | 316 | } |
77 | 317 | ||
78 | void cpufreq_put_available_governors(struct cpufreq_available_governors *any) | 318 | void cpufreq_put_available_governors(struct cpufreq_available_governors *any) |
@@ -96,7 +336,57 @@ void cpufreq_put_available_governors(struct cpufreq_available_governors *any) | |||
96 | struct cpufreq_available_frequencies | 336 | struct cpufreq_available_frequencies |
97 | *cpufreq_get_available_frequencies(unsigned int cpu) | 337 | *cpufreq_get_available_frequencies(unsigned int cpu) |
98 | { | 338 | { |
99 | return sysfs_get_available_frequencies(cpu); | 339 | struct cpufreq_available_frequencies *first = NULL; |
340 | struct cpufreq_available_frequencies *current = NULL; | ||
341 | char one_value[SYSFS_PATH_MAX]; | ||
342 | char linebuf[MAX_LINE_LEN]; | ||
343 | unsigned int pos, i; | ||
344 | unsigned int len; | ||
345 | |||
346 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | ||
347 | linebuf, sizeof(linebuf)); | ||
348 | if (len == 0) | ||
349 | return NULL; | ||
350 | |||
351 | pos = 0; | ||
352 | for (i = 0; i < len; i++) { | ||
353 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
354 | if (i - pos < 2) | ||
355 | continue; | ||
356 | if (i - pos >= SYSFS_PATH_MAX) | ||
357 | goto error_out; | ||
358 | if (current) { | ||
359 | current->next = malloc(sizeof(*current)); | ||
360 | if (!current->next) | ||
361 | goto error_out; | ||
362 | current = current->next; | ||
363 | } else { | ||
364 | first = malloc(sizeof(*first)); | ||
365 | if (!first) | ||
366 | goto error_out; | ||
367 | current = first; | ||
368 | } | ||
369 | current->first = first; | ||
370 | current->next = NULL; | ||
371 | |||
372 | memcpy(one_value, linebuf + pos, i - pos); | ||
373 | one_value[i - pos] = '\0'; | ||
374 | if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | ||
375 | goto error_out; | ||
376 | |||
377 | pos = i + 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | return first; | ||
382 | |||
383 | error_out: | ||
384 | while (first) { | ||
385 | current = first->next; | ||
386 | free(first); | ||
387 | first = current; | ||
388 | } | ||
389 | return NULL; | ||
100 | } | 390 | } |
101 | 391 | ||
102 | void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies | 392 | void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies |
@@ -114,10 +404,65 @@ void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies | |||
114 | } | 404 | } |
115 | } | 405 | } |
116 | 406 | ||
407 | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | ||
408 | const char *file) | ||
409 | { | ||
410 | struct cpufreq_affected_cpus *first = NULL; | ||
411 | struct cpufreq_affected_cpus *current = NULL; | ||
412 | char one_value[SYSFS_PATH_MAX]; | ||
413 | char linebuf[MAX_LINE_LEN]; | ||
414 | unsigned int pos, i; | ||
415 | unsigned int len; | ||
416 | |||
417 | len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | ||
418 | if (len == 0) | ||
419 | return NULL; | ||
420 | |||
421 | pos = 0; | ||
422 | for (i = 0; i < len; i++) { | ||
423 | if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
424 | if (i - pos < 1) | ||
425 | continue; | ||
426 | if (i - pos >= SYSFS_PATH_MAX) | ||
427 | goto error_out; | ||
428 | if (current) { | ||
429 | current->next = malloc(sizeof(*current)); | ||
430 | if (!current->next) | ||
431 | goto error_out; | ||
432 | current = current->next; | ||
433 | } else { | ||
434 | first = malloc(sizeof(*first)); | ||
435 | if (!first) | ||
436 | goto error_out; | ||
437 | current = first; | ||
438 | } | ||
439 | current->first = first; | ||
440 | current->next = NULL; | ||
441 | |||
442 | memcpy(one_value, linebuf + pos, i - pos); | ||
443 | one_value[i - pos] = '\0'; | ||
444 | |||
445 | if (sscanf(one_value, "%u", ¤t->cpu) != 1) | ||
446 | goto error_out; | ||
447 | |||
448 | pos = i + 1; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | return first; | ||
453 | |||
454 | error_out: | ||
455 | while (first) { | ||
456 | current = first->next; | ||
457 | free(first); | ||
458 | first = current; | ||
459 | } | ||
460 | return NULL; | ||
461 | } | ||
117 | 462 | ||
118 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) | 463 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) |
119 | { | 464 | { |
120 | return sysfs_get_freq_affected_cpus(cpu); | 465 | return sysfs_get_cpu_list(cpu, "affected_cpus"); |
121 | } | 466 | } |
122 | 467 | ||
123 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) | 468 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) |
@@ -138,7 +483,7 @@ void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) | |||
138 | 483 | ||
139 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) | 484 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) |
140 | { | 485 | { |
141 | return sysfs_get_freq_related_cpus(cpu); | 486 | return sysfs_get_cpu_list(cpu, "related_cpus"); |
142 | } | 487 | } |
143 | 488 | ||
144 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) | 489 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) |
@@ -146,45 +491,208 @@ void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) | |||
146 | cpufreq_put_affected_cpus(any); | 491 | cpufreq_put_affected_cpus(any); |
147 | } | 492 | } |
148 | 493 | ||
494 | static int verify_gov(char *new_gov, char *passed_gov) | ||
495 | { | ||
496 | unsigned int i, j = 0; | ||
497 | |||
498 | if (!passed_gov || (strlen(passed_gov) > 19)) | ||
499 | return -EINVAL; | ||
500 | |||
501 | strncpy(new_gov, passed_gov, 20); | ||
502 | for (i = 0; i < 20; i++) { | ||
503 | if (j) { | ||
504 | new_gov[i] = '\0'; | ||
505 | continue; | ||
506 | } | ||
507 | if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | ||
508 | continue; | ||
509 | |||
510 | if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | ||
511 | continue; | ||
512 | |||
513 | if (new_gov[i] == '-') | ||
514 | continue; | ||
515 | |||
516 | if (new_gov[i] == '_') | ||
517 | continue; | ||
518 | |||
519 | if (new_gov[i] == '\0') { | ||
520 | j = 1; | ||
521 | continue; | ||
522 | } | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | new_gov[19] = '\0'; | ||
526 | return 0; | ||
527 | } | ||
149 | 528 | ||
150 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) | 529 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) |
151 | { | 530 | { |
531 | char min[SYSFS_PATH_MAX]; | ||
532 | char max[SYSFS_PATH_MAX]; | ||
533 | char gov[SYSFS_PATH_MAX]; | ||
534 | int ret; | ||
535 | unsigned long old_min; | ||
536 | int write_max_first; | ||
537 | |||
152 | if (!policy || !(policy->governor)) | 538 | if (!policy || !(policy->governor)) |
153 | return -EINVAL; | 539 | return -EINVAL; |
154 | 540 | ||
155 | return sysfs_set_freq_policy(cpu, policy); | 541 | if (policy->max < policy->min) |
542 | return -EINVAL; | ||
543 | |||
544 | if (verify_gov(gov, policy->governor)) | ||
545 | return -EINVAL; | ||
546 | |||
547 | snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | ||
548 | snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | ||
549 | |||
550 | old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
551 | write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | ||
552 | |||
553 | if (write_max_first) { | ||
554 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
555 | max, strlen(max)); | ||
556 | if (ret) | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | ||
561 | strlen(min)); | ||
562 | if (ret) | ||
563 | return ret; | ||
564 | |||
565 | if (!write_max_first) { | ||
566 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
567 | max, strlen(max)); | ||
568 | if (ret) | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
573 | gov, strlen(gov)); | ||
156 | } | 574 | } |
157 | 575 | ||
158 | 576 | ||
159 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) | 577 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) |
160 | { | 578 | { |
161 | return sysfs_modify_freq_policy_min(cpu, min_freq); | 579 | char value[SYSFS_PATH_MAX]; |
580 | |||
581 | snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | ||
582 | |||
583 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | ||
584 | value, strlen(value)); | ||
162 | } | 585 | } |
163 | 586 | ||
164 | 587 | ||
165 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) | 588 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) |
166 | { | 589 | { |
167 | return sysfs_modify_freq_policy_max(cpu, max_freq); | 590 | char value[SYSFS_PATH_MAX]; |
168 | } | 591 | |
592 | snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | ||
169 | 593 | ||
594 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
595 | value, strlen(value)); | ||
596 | } | ||
170 | 597 | ||
171 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) | 598 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) |
172 | { | 599 | { |
600 | char new_gov[SYSFS_PATH_MAX]; | ||
601 | |||
173 | if ((!governor) || (strlen(governor) > 19)) | 602 | if ((!governor) || (strlen(governor) > 19)) |
174 | return -EINVAL; | 603 | return -EINVAL; |
175 | 604 | ||
176 | return sysfs_modify_freq_policy_governor(cpu, governor); | 605 | if (verify_gov(new_gov, governor)) |
606 | return -EINVAL; | ||
607 | |||
608 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
609 | new_gov, strlen(new_gov)); | ||
177 | } | 610 | } |
178 | 611 | ||
179 | int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) | 612 | int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) |
180 | { | 613 | { |
181 | return sysfs_set_frequency(cpu, target_frequency); | 614 | struct cpufreq_policy *pol = cpufreq_get_policy(cpu); |
615 | char userspace_gov[] = "userspace"; | ||
616 | char freq[SYSFS_PATH_MAX]; | ||
617 | int ret; | ||
618 | |||
619 | if (!pol) | ||
620 | return -ENODEV; | ||
621 | |||
622 | if (strncmp(pol->governor, userspace_gov, 9) != 0) { | ||
623 | ret = cpufreq_modify_policy_governor(cpu, userspace_gov); | ||
624 | if (ret) { | ||
625 | cpufreq_put_policy(pol); | ||
626 | return ret; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | cpufreq_put_policy(pol); | ||
631 | |||
632 | snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | ||
633 | |||
634 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | ||
635 | freq, strlen(freq)); | ||
182 | } | 636 | } |
183 | 637 | ||
184 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | 638 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, |
185 | unsigned long long *total_time) | 639 | unsigned long long *total_time) |
186 | { | 640 | { |
187 | return sysfs_get_freq_stats(cpu, total_time); | 641 | struct cpufreq_stats *first = NULL; |
642 | struct cpufreq_stats *current = NULL; | ||
643 | char one_value[SYSFS_PATH_MAX]; | ||
644 | char linebuf[MAX_LINE_LEN]; | ||
645 | unsigned int pos, i; | ||
646 | unsigned int len; | ||
647 | |||
648 | len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | ||
649 | linebuf, sizeof(linebuf)); | ||
650 | if (len == 0) | ||
651 | return NULL; | ||
652 | |||
653 | *total_time = 0; | ||
654 | pos = 0; | ||
655 | for (i = 0; i < len; i++) { | ||
656 | if (i == strlen(linebuf) || linebuf[i] == '\n') { | ||
657 | if (i - pos < 2) | ||
658 | continue; | ||
659 | if ((i - pos) >= SYSFS_PATH_MAX) | ||
660 | goto error_out; | ||
661 | if (current) { | ||
662 | current->next = malloc(sizeof(*current)); | ||
663 | if (!current->next) | ||
664 | goto error_out; | ||
665 | current = current->next; | ||
666 | } else { | ||
667 | first = malloc(sizeof(*first)); | ||
668 | if (!first) | ||
669 | goto error_out; | ||
670 | current = first; | ||
671 | } | ||
672 | current->first = first; | ||
673 | current->next = NULL; | ||
674 | |||
675 | memcpy(one_value, linebuf + pos, i - pos); | ||
676 | one_value[i - pos] = '\0'; | ||
677 | if (sscanf(one_value, "%lu %llu", | ||
678 | ¤t->frequency, | ||
679 | ¤t->time_in_state) != 2) | ||
680 | goto error_out; | ||
681 | |||
682 | *total_time = *total_time + current->time_in_state; | ||
683 | pos = i + 1; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | return first; | ||
688 | |||
689 | error_out: | ||
690 | while (first) { | ||
691 | current = first->next; | ||
692 | free(first); | ||
693 | first = current; | ||
694 | } | ||
695 | return NULL; | ||
188 | } | 696 | } |
189 | 697 | ||
190 | void cpufreq_put_stats(struct cpufreq_stats *any) | 698 | void cpufreq_put_stats(struct cpufreq_stats *any) |
@@ -204,5 +712,5 @@ void cpufreq_put_stats(struct cpufreq_stats *any) | |||
204 | 712 | ||
205 | unsigned long cpufreq_get_transitions(unsigned int cpu) | 713 | unsigned long cpufreq_get_transitions(unsigned int cpu) |
206 | { | 714 | { |
207 | return sysfs_get_freq_transitions(cpu); | 715 | return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); |
208 | } | 716 | } |
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h index 3aae8e7a0839..3b005c39f068 100644 --- a/tools/power/cpupower/lib/cpufreq.h +++ b/tools/power/cpupower/lib/cpufreq.h | |||
@@ -17,8 +17,8 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef _CPUFREQ_H | 20 | #ifndef __CPUPOWER_CPUFREQ_H__ |
21 | #define _CPUFREQ_H 1 | 21 | #define __CPUPOWER_CPUFREQ_H__ |
22 | 22 | ||
23 | struct cpufreq_policy { | 23 | struct cpufreq_policy { |
24 | unsigned long min; | 24 | unsigned long min; |
@@ -58,13 +58,6 @@ struct cpufreq_stats { | |||
58 | extern "C" { | 58 | extern "C" { |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | /* | ||
62 | * returns 0 if the specified CPU is present (it doesn't say | ||
63 | * whether it is online!), and an error value if not. | ||
64 | */ | ||
65 | |||
66 | extern int cpufreq_cpu_exists(unsigned int cpu); | ||
67 | |||
68 | /* determine current CPU frequency | 61 | /* determine current CPU frequency |
69 | * - _kernel variant means kernel's opinion of CPU frequency | 62 | * - _kernel variant means kernel's opinion of CPU frequency |
70 | * - _hardware variant means actual hardware CPU frequency, | 63 | * - _hardware variant means actual hardware CPU frequency, |
@@ -73,9 +66,9 @@ extern int cpufreq_cpu_exists(unsigned int cpu); | |||
73 | * returns 0 on failure, else frequency in kHz. | 66 | * returns 0 on failure, else frequency in kHz. |
74 | */ | 67 | */ |
75 | 68 | ||
76 | extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu); | 69 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu); |
77 | 70 | ||
78 | extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); | 71 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu); |
79 | 72 | ||
80 | #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); | 73 | #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); |
81 | 74 | ||
@@ -84,7 +77,7 @@ extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); | |||
84 | * | 77 | * |
85 | * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds | 78 | * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds |
86 | */ | 79 | */ |
87 | extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); | 80 | unsigned long cpufreq_get_transition_latency(unsigned int cpu); |
88 | 81 | ||
89 | 82 | ||
90 | /* determine hardware CPU frequency limits | 83 | /* determine hardware CPU frequency limits |
@@ -93,7 +86,7 @@ extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); | |||
93 | * considerations by cpufreq policy notifiers in the kernel. | 86 | * considerations by cpufreq policy notifiers in the kernel. |
94 | */ | 87 | */ |
95 | 88 | ||
96 | extern int cpufreq_get_hardware_limits(unsigned int cpu, | 89 | int cpufreq_get_hardware_limits(unsigned int cpu, |
97 | unsigned long *min, | 90 | unsigned long *min, |
98 | unsigned long *max); | 91 | unsigned long *max); |
99 | 92 | ||
@@ -104,9 +97,9 @@ extern int cpufreq_get_hardware_limits(unsigned int cpu, | |||
104 | * to avoid memory leakage, please. | 97 | * to avoid memory leakage, please. |
105 | */ | 98 | */ |
106 | 99 | ||
107 | extern char *cpufreq_get_driver(unsigned int cpu); | 100 | char *cpufreq_get_driver(unsigned int cpu); |
108 | 101 | ||
109 | extern void cpufreq_put_driver(char *ptr); | 102 | void cpufreq_put_driver(char *ptr); |
110 | 103 | ||
111 | 104 | ||
112 | /* determine CPUfreq policy currently used | 105 | /* determine CPUfreq policy currently used |
@@ -116,9 +109,9 @@ extern void cpufreq_put_driver(char *ptr); | |||
116 | */ | 109 | */ |
117 | 110 | ||
118 | 111 | ||
119 | extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); | 112 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); |
120 | 113 | ||
121 | extern void cpufreq_put_policy(struct cpufreq_policy *policy); | 114 | void cpufreq_put_policy(struct cpufreq_policy *policy); |
122 | 115 | ||
123 | 116 | ||
124 | /* determine CPUfreq governors currently available | 117 | /* determine CPUfreq governors currently available |
@@ -129,10 +122,10 @@ extern void cpufreq_put_policy(struct cpufreq_policy *policy); | |||
129 | */ | 122 | */ |
130 | 123 | ||
131 | 124 | ||
132 | extern struct cpufreq_available_governors | 125 | struct cpufreq_available_governors |
133 | *cpufreq_get_available_governors(unsigned int cpu); | 126 | *cpufreq_get_available_governors(unsigned int cpu); |
134 | 127 | ||
135 | extern void cpufreq_put_available_governors( | 128 | void cpufreq_put_available_governors( |
136 | struct cpufreq_available_governors *first); | 129 | struct cpufreq_available_governors *first); |
137 | 130 | ||
138 | 131 | ||
@@ -143,10 +136,10 @@ extern void cpufreq_put_available_governors( | |||
143 | * cpufreq_put_available_frequencies after use. | 136 | * cpufreq_put_available_frequencies after use. |
144 | */ | 137 | */ |
145 | 138 | ||
146 | extern struct cpufreq_available_frequencies | 139 | struct cpufreq_available_frequencies |
147 | *cpufreq_get_available_frequencies(unsigned int cpu); | 140 | *cpufreq_get_available_frequencies(unsigned int cpu); |
148 | 141 | ||
149 | extern void cpufreq_put_available_frequencies( | 142 | void cpufreq_put_available_frequencies( |
150 | struct cpufreq_available_frequencies *first); | 143 | struct cpufreq_available_frequencies *first); |
151 | 144 | ||
152 | 145 | ||
@@ -156,10 +149,10 @@ extern void cpufreq_put_available_frequencies( | |||
156 | * to avoid memory leakage, please. | 149 | * to avoid memory leakage, please. |
157 | */ | 150 | */ |
158 | 151 | ||
159 | extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned | 152 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned |
160 | int cpu); | 153 | int cpu); |
161 | 154 | ||
162 | extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); | 155 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); |
163 | 156 | ||
164 | 157 | ||
165 | /* determine related CPUs | 158 | /* determine related CPUs |
@@ -168,10 +161,10 @@ extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); | |||
168 | * to avoid memory leakage, please. | 161 | * to avoid memory leakage, please. |
169 | */ | 162 | */ |
170 | 163 | ||
171 | extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned | 164 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned |
172 | int cpu); | 165 | int cpu); |
173 | 166 | ||
174 | extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); | 167 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); |
175 | 168 | ||
176 | 169 | ||
177 | /* determine stats for cpufreq subsystem | 170 | /* determine stats for cpufreq subsystem |
@@ -179,12 +172,12 @@ extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); | |||
179 | * This is not available in all kernel versions or configurations. | 172 | * This is not available in all kernel versions or configurations. |
180 | */ | 173 | */ |
181 | 174 | ||
182 | extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | 175 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, |
183 | unsigned long long *total_time); | 176 | unsigned long long *total_time); |
184 | 177 | ||
185 | extern void cpufreq_put_stats(struct cpufreq_stats *stats); | 178 | void cpufreq_put_stats(struct cpufreq_stats *stats); |
186 | 179 | ||
187 | extern unsigned long cpufreq_get_transitions(unsigned int cpu); | 180 | unsigned long cpufreq_get_transitions(unsigned int cpu); |
188 | 181 | ||
189 | 182 | ||
190 | /* set new cpufreq policy | 183 | /* set new cpufreq policy |
@@ -193,7 +186,7 @@ extern unsigned long cpufreq_get_transitions(unsigned int cpu); | |||
193 | * but results may differ depending e.g. on governors being available. | 186 | * but results may differ depending e.g. on governors being available. |
194 | */ | 187 | */ |
195 | 188 | ||
196 | extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); | 189 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); |
197 | 190 | ||
198 | 191 | ||
199 | /* modify a policy by only changing min/max freq or governor | 192 | /* modify a policy by only changing min/max freq or governor |
@@ -201,9 +194,9 @@ extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); | |||
201 | * Does not check whether result is what was intended. | 194 | * Does not check whether result is what was intended. |
202 | */ | 195 | */ |
203 | 196 | ||
204 | extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); | 197 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); |
205 | extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); | 198 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); |
206 | extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); | 199 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); |
207 | 200 | ||
208 | 201 | ||
209 | /* set a specific frequency | 202 | /* set a specific frequency |
@@ -213,7 +206,7 @@ extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); | |||
213 | * occurs. Also does not work on ->range() cpufreq drivers. | 206 | * occurs. Also does not work on ->range() cpufreq drivers. |
214 | */ | 207 | */ |
215 | 208 | ||
216 | extern int cpufreq_set_frequency(unsigned int cpu, | 209 | int cpufreq_set_frequency(unsigned int cpu, |
217 | unsigned long target_frequency); | 210 | unsigned long target_frequency); |
218 | 211 | ||
219 | #ifdef __cplusplus | 212 | #ifdef __cplusplus |
diff --git a/tools/power/cpupower/lib/cpuidle.c b/tools/power/cpupower/lib/cpuidle.c new file mode 100644 index 000000000000..9bd4c7655fdb --- /dev/null +++ b/tools/power/cpupower/lib/cpuidle.c | |||
@@ -0,0 +1,380 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc. | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <errno.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "cpuidle.h" | ||
18 | #include "cpupower_intern.h" | ||
19 | |||
20 | /* | ||
21 | * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir | ||
22 | * exists. | ||
23 | * For example the functionality to disable c-states was introduced in later | ||
24 | * kernel versions, this function can be used to explicitly check for this | ||
25 | * feature. | ||
26 | * | ||
27 | * returns 1 if the file exists, 0 otherwise. | ||
28 | */ | ||
29 | static | ||
30 | unsigned int cpuidle_state_file_exists(unsigned int cpu, | ||
31 | unsigned int idlestate, | ||
32 | const char *fname) | ||
33 | { | ||
34 | char path[SYSFS_PATH_MAX]; | ||
35 | struct stat statbuf; | ||
36 | |||
37 | |||
38 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
39 | cpu, idlestate, fname); | ||
40 | if (stat(path, &statbuf) != 0) | ||
41 | return 0; | ||
42 | return 1; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * helper function to read file from /sys into given buffer | ||
47 | * fname is a relative path under "cpuX/cpuidle/stateX/" dir | ||
48 | * cstates starting with 0, C0 is not counted as cstate. | ||
49 | * This means if you want C1 info, pass 0 as idlestate param | ||
50 | */ | ||
51 | static | ||
52 | unsigned int cpuidle_state_read_file(unsigned int cpu, | ||
53 | unsigned int idlestate, | ||
54 | const char *fname, char *buf, | ||
55 | size_t buflen) | ||
56 | { | ||
57 | char path[SYSFS_PATH_MAX]; | ||
58 | int fd; | ||
59 | ssize_t numread; | ||
60 | |||
61 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
62 | cpu, idlestate, fname); | ||
63 | |||
64 | fd = open(path, O_RDONLY); | ||
65 | if (fd == -1) | ||
66 | return 0; | ||
67 | |||
68 | numread = read(fd, buf, buflen - 1); | ||
69 | if (numread < 1) { | ||
70 | close(fd); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | buf[numread] = '\0'; | ||
75 | close(fd); | ||
76 | |||
77 | return (unsigned int) numread; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * helper function to write a new value to a /sys file | ||
82 | * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir | ||
83 | * | ||
84 | * Returns the number of bytes written or 0 on error | ||
85 | */ | ||
86 | static | ||
87 | unsigned int cpuidle_state_write_file(unsigned int cpu, | ||
88 | unsigned int idlestate, | ||
89 | const char *fname, | ||
90 | const char *value, size_t len) | ||
91 | { | ||
92 | char path[SYSFS_PATH_MAX]; | ||
93 | int fd; | ||
94 | ssize_t numwrite; | ||
95 | |||
96 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
97 | cpu, idlestate, fname); | ||
98 | |||
99 | fd = open(path, O_WRONLY); | ||
100 | if (fd == -1) | ||
101 | return 0; | ||
102 | |||
103 | numwrite = write(fd, value, len); | ||
104 | if (numwrite < 1) { | ||
105 | close(fd); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | close(fd); | ||
110 | |||
111 | return (unsigned int) numwrite; | ||
112 | } | ||
113 | |||
114 | /* read access to files which contain one numeric value */ | ||
115 | |||
116 | enum idlestate_value { | ||
117 | IDLESTATE_USAGE, | ||
118 | IDLESTATE_POWER, | ||
119 | IDLESTATE_LATENCY, | ||
120 | IDLESTATE_TIME, | ||
121 | IDLESTATE_DISABLE, | ||
122 | MAX_IDLESTATE_VALUE_FILES | ||
123 | }; | ||
124 | |||
125 | static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { | ||
126 | [IDLESTATE_USAGE] = "usage", | ||
127 | [IDLESTATE_POWER] = "power", | ||
128 | [IDLESTATE_LATENCY] = "latency", | ||
129 | [IDLESTATE_TIME] = "time", | ||
130 | [IDLESTATE_DISABLE] = "disable", | ||
131 | }; | ||
132 | |||
133 | static | ||
134 | unsigned long long cpuidle_state_get_one_value(unsigned int cpu, | ||
135 | unsigned int idlestate, | ||
136 | enum idlestate_value which) | ||
137 | { | ||
138 | unsigned long long value; | ||
139 | unsigned int len; | ||
140 | char linebuf[MAX_LINE_LEN]; | ||
141 | char *endp; | ||
142 | |||
143 | if (which >= MAX_IDLESTATE_VALUE_FILES) | ||
144 | return 0; | ||
145 | |||
146 | len = cpuidle_state_read_file(cpu, idlestate, | ||
147 | idlestate_value_files[which], | ||
148 | linebuf, sizeof(linebuf)); | ||
149 | if (len == 0) | ||
150 | return 0; | ||
151 | |||
152 | value = strtoull(linebuf, &endp, 0); | ||
153 | |||
154 | if (endp == linebuf || errno == ERANGE) | ||
155 | return 0; | ||
156 | |||
157 | return value; | ||
158 | } | ||
159 | |||
160 | /* read access to files which contain one string */ | ||
161 | |||
162 | enum idlestate_string { | ||
163 | IDLESTATE_DESC, | ||
164 | IDLESTATE_NAME, | ||
165 | MAX_IDLESTATE_STRING_FILES | ||
166 | }; | ||
167 | |||
168 | static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { | ||
169 | [IDLESTATE_DESC] = "desc", | ||
170 | [IDLESTATE_NAME] = "name", | ||
171 | }; | ||
172 | |||
173 | |||
174 | static char *cpuidle_state_get_one_string(unsigned int cpu, | ||
175 | unsigned int idlestate, | ||
176 | enum idlestate_string which) | ||
177 | { | ||
178 | char linebuf[MAX_LINE_LEN]; | ||
179 | char *result; | ||
180 | unsigned int len; | ||
181 | |||
182 | if (which >= MAX_IDLESTATE_STRING_FILES) | ||
183 | return NULL; | ||
184 | |||
185 | len = cpuidle_state_read_file(cpu, idlestate, | ||
186 | idlestate_string_files[which], | ||
187 | linebuf, sizeof(linebuf)); | ||
188 | if (len == 0) | ||
189 | return NULL; | ||
190 | |||
191 | result = strdup(linebuf); | ||
192 | if (result == NULL) | ||
193 | return NULL; | ||
194 | |||
195 | if (result[strlen(result) - 1] == '\n') | ||
196 | result[strlen(result) - 1] = '\0'; | ||
197 | |||
198 | return result; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Returns: | ||
203 | * 1 if disabled | ||
204 | * 0 if enabled | ||
205 | * -1 if idlestate is not available | ||
206 | * -2 if disabling is not supported by the kernel | ||
207 | */ | ||
208 | int cpuidle_is_state_disabled(unsigned int cpu, | ||
209 | unsigned int idlestate) | ||
210 | { | ||
211 | if (cpuidle_state_count(cpu) <= idlestate) | ||
212 | return -1; | ||
213 | |||
214 | if (!cpuidle_state_file_exists(cpu, idlestate, | ||
215 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
216 | return -2; | ||
217 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Pass 1 as last argument to disable or 0 to enable the state | ||
222 | * Returns: | ||
223 | * 0 on success | ||
224 | * negative values on error, for example: | ||
225 | * -1 if idlestate is not available | ||
226 | * -2 if disabling is not supported by the kernel | ||
227 | * -3 No write access to disable/enable C-states | ||
228 | */ | ||
229 | int cpuidle_state_disable(unsigned int cpu, | ||
230 | unsigned int idlestate, | ||
231 | unsigned int disable) | ||
232 | { | ||
233 | char value[SYSFS_PATH_MAX]; | ||
234 | int bytes_written; | ||
235 | |||
236 | if (cpuidle_state_count(cpu) <= idlestate) | ||
237 | return -1; | ||
238 | |||
239 | if (!cpuidle_state_file_exists(cpu, idlestate, | ||
240 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
241 | return -2; | ||
242 | |||
243 | snprintf(value, SYSFS_PATH_MAX, "%u", disable); | ||
244 | |||
245 | bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable", | ||
246 | value, sizeof(disable)); | ||
247 | if (bytes_written) | ||
248 | return 0; | ||
249 | return -3; | ||
250 | } | ||
251 | |||
252 | unsigned long cpuidle_state_latency(unsigned int cpu, | ||
253 | unsigned int idlestate) | ||
254 | { | ||
255 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); | ||
256 | } | ||
257 | |||
258 | unsigned long cpuidle_state_usage(unsigned int cpu, | ||
259 | unsigned int idlestate) | ||
260 | { | ||
261 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE); | ||
262 | } | ||
263 | |||
264 | unsigned long long cpuidle_state_time(unsigned int cpu, | ||
265 | unsigned int idlestate) | ||
266 | { | ||
267 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME); | ||
268 | } | ||
269 | |||
270 | char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate) | ||
271 | { | ||
272 | return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME); | ||
273 | } | ||
274 | |||
275 | char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate) | ||
276 | { | ||
277 | return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Returns number of supported C-states of CPU core cpu | ||
282 | * Negativ in error case | ||
283 | * Zero if cpuidle does not export any C-states | ||
284 | */ | ||
285 | unsigned int cpuidle_state_count(unsigned int cpu) | ||
286 | { | ||
287 | char file[SYSFS_PATH_MAX]; | ||
288 | struct stat statbuf; | ||
289 | int idlestates = 1; | ||
290 | |||
291 | |||
292 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); | ||
293 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
294 | return 0; | ||
295 | |||
296 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); | ||
297 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
298 | return 0; | ||
299 | |||
300 | while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { | ||
301 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU | ||
302 | "cpu%u/cpuidle/state%d", cpu, idlestates); | ||
303 | idlestates++; | ||
304 | } | ||
305 | idlestates--; | ||
306 | return idlestates; | ||
307 | } | ||
308 | |||
309 | /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ | ||
310 | |||
311 | /* | ||
312 | * helper function to read file from /sys into given buffer | ||
313 | * fname is a relative path under "cpu/cpuidle/" dir | ||
314 | */ | ||
315 | static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, | ||
316 | size_t buflen) | ||
317 | { | ||
318 | char path[SYSFS_PATH_MAX]; | ||
319 | |||
320 | snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); | ||
321 | |||
322 | return sysfs_read_file(path, buf, buflen); | ||
323 | } | ||
324 | |||
325 | |||
326 | |||
327 | /* read access to files which contain one string */ | ||
328 | |||
329 | enum cpuidle_string { | ||
330 | CPUIDLE_GOVERNOR, | ||
331 | CPUIDLE_GOVERNOR_RO, | ||
332 | CPUIDLE_DRIVER, | ||
333 | MAX_CPUIDLE_STRING_FILES | ||
334 | }; | ||
335 | |||
336 | static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { | ||
337 | [CPUIDLE_GOVERNOR] = "current_governor", | ||
338 | [CPUIDLE_GOVERNOR_RO] = "current_governor_ro", | ||
339 | [CPUIDLE_DRIVER] = "current_driver", | ||
340 | }; | ||
341 | |||
342 | |||
343 | static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) | ||
344 | { | ||
345 | char linebuf[MAX_LINE_LEN]; | ||
346 | char *result; | ||
347 | unsigned int len; | ||
348 | |||
349 | if (which >= MAX_CPUIDLE_STRING_FILES) | ||
350 | return NULL; | ||
351 | |||
352 | len = sysfs_cpuidle_read_file(cpuidle_string_files[which], | ||
353 | linebuf, sizeof(linebuf)); | ||
354 | if (len == 0) | ||
355 | return NULL; | ||
356 | |||
357 | result = strdup(linebuf); | ||
358 | if (result == NULL) | ||
359 | return NULL; | ||
360 | |||
361 | if (result[strlen(result) - 1] == '\n') | ||
362 | result[strlen(result) - 1] = '\0'; | ||
363 | |||
364 | return result; | ||
365 | } | ||
366 | |||
367 | char *cpuidle_get_governor(void) | ||
368 | { | ||
369 | char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); | ||
370 | if (!tmp) | ||
371 | return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); | ||
372 | else | ||
373 | return tmp; | ||
374 | } | ||
375 | |||
376 | char *cpuidle_get_driver(void) | ||
377 | { | ||
378 | return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); | ||
379 | } | ||
380 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | ||
diff --git a/tools/power/cpupower/lib/cpuidle.h b/tools/power/cpupower/lib/cpuidle.h new file mode 100644 index 000000000000..04eb3cfa6e42 --- /dev/null +++ b/tools/power/cpupower/lib/cpuidle.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef __CPUPOWER_CPUIDLE_H__ | ||
2 | #define __CPUPOWER_CPUIDLE_H__ | ||
3 | |||
4 | int cpuidle_is_state_disabled(unsigned int cpu, | ||
5 | unsigned int idlestate); | ||
6 | int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate, | ||
7 | unsigned int disable); | ||
8 | unsigned long cpuidle_state_latency(unsigned int cpu, | ||
9 | unsigned int idlestate); | ||
10 | unsigned long cpuidle_state_usage(unsigned int cpu, | ||
11 | unsigned int idlestate); | ||
12 | unsigned long long cpuidle_state_time(unsigned int cpu, | ||
13 | unsigned int idlestate); | ||
14 | char *cpuidle_state_name(unsigned int cpu, | ||
15 | unsigned int idlestate); | ||
16 | char *cpuidle_state_desc(unsigned int cpu, | ||
17 | unsigned int idlestate); | ||
18 | unsigned int cpuidle_state_count(unsigned int cpu); | ||
19 | |||
20 | char *cpuidle_get_governor(void); | ||
21 | char *cpuidle_get_driver(void); | ||
22 | |||
23 | #endif /* __CPUPOWER_HELPERS_SYSFS_H__ */ | ||
diff --git a/tools/power/cpupower/lib/cpupower.c b/tools/power/cpupower/lib/cpupower.c new file mode 100644 index 000000000000..9c395ec924de --- /dev/null +++ b/tools/power/cpupower/lib/cpupower.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <fcntl.h> | ||
10 | #include <unistd.h> | ||
11 | #include <stdio.h> | ||
12 | #include <errno.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | #include "cpupower.h" | ||
16 | #include "cpupower_intern.h" | ||
17 | |||
18 | unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
19 | { | ||
20 | int fd; | ||
21 | ssize_t numread; | ||
22 | |||
23 | fd = open(path, O_RDONLY); | ||
24 | if (fd == -1) | ||
25 | return 0; | ||
26 | |||
27 | numread = read(fd, buf, buflen - 1); | ||
28 | if (numread < 1) { | ||
29 | close(fd); | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | buf[numread] = '\0'; | ||
34 | close(fd); | ||
35 | |||
36 | return (unsigned int) numread; | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * Detect whether a CPU is online | ||
41 | * | ||
42 | * Returns: | ||
43 | * 1 -> if CPU is online | ||
44 | * 0 -> if CPU is offline | ||
45 | * negative errno values in error case | ||
46 | */ | ||
47 | int cpupower_is_cpu_online(unsigned int cpu) | ||
48 | { | ||
49 | char path[SYSFS_PATH_MAX]; | ||
50 | int fd; | ||
51 | ssize_t numread; | ||
52 | unsigned long long value; | ||
53 | char linebuf[MAX_LINE_LEN]; | ||
54 | char *endp; | ||
55 | struct stat statbuf; | ||
56 | |||
57 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); | ||
58 | |||
59 | if (stat(path, &statbuf) != 0) | ||
60 | return 0; | ||
61 | |||
62 | /* | ||
63 | * kernel without CONFIG_HOTPLUG_CPU | ||
64 | * -> cpuX directory exists, but not cpuX/online file | ||
65 | */ | ||
66 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); | ||
67 | if (stat(path, &statbuf) != 0) | ||
68 | return 1; | ||
69 | |||
70 | fd = open(path, O_RDONLY); | ||
71 | if (fd == -1) | ||
72 | return -errno; | ||
73 | |||
74 | numread = read(fd, linebuf, MAX_LINE_LEN - 1); | ||
75 | if (numread < 1) { | ||
76 | close(fd); | ||
77 | return -EIO; | ||
78 | } | ||
79 | linebuf[numread] = '\0'; | ||
80 | close(fd); | ||
81 | |||
82 | value = strtoull(linebuf, &endp, 0); | ||
83 | if (value > 1) | ||
84 | return -EINVAL; | ||
85 | |||
86 | return value; | ||
87 | } | ||
88 | |||
89 | /* returns -1 on failure, 0 on success */ | ||
90 | static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) | ||
91 | { | ||
92 | char linebuf[MAX_LINE_LEN]; | ||
93 | char *endp; | ||
94 | char path[SYSFS_PATH_MAX]; | ||
95 | |||
96 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
97 | cpu, fname); | ||
98 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
99 | return -1; | ||
100 | *result = strtol(linebuf, &endp, 0); | ||
101 | if (endp == linebuf || errno == ERANGE) | ||
102 | return -1; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int __compare(const void *t1, const void *t2) | ||
107 | { | ||
108 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
109 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
110 | if (top1->pkg < top2->pkg) | ||
111 | return -1; | ||
112 | else if (top1->pkg > top2->pkg) | ||
113 | return 1; | ||
114 | else if (top1->core < top2->core) | ||
115 | return -1; | ||
116 | else if (top1->core > top2->core) | ||
117 | return 1; | ||
118 | else if (top1->cpu < top2->cpu) | ||
119 | return -1; | ||
120 | else if (top1->cpu > top2->cpu) | ||
121 | return 1; | ||
122 | else | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Returns amount of cpus, negative on error, cpu_top must be | ||
128 | * passed to cpu_topology_release to free resources | ||
129 | * | ||
130 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
131 | */ | ||
132 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
133 | { | ||
134 | int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
135 | |||
136 | cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); | ||
137 | if (cpu_top->core_info == NULL) | ||
138 | return -ENOMEM; | ||
139 | cpu_top->pkgs = cpu_top->cores = 0; | ||
140 | for (cpu = 0; cpu < cpus; cpu++) { | ||
141 | cpu_top->core_info[cpu].cpu = cpu; | ||
142 | cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu); | ||
143 | if(sysfs_topology_read_file( | ||
144 | cpu, | ||
145 | "physical_package_id", | ||
146 | &(cpu_top->core_info[cpu].pkg)) < 0) { | ||
147 | cpu_top->core_info[cpu].pkg = -1; | ||
148 | cpu_top->core_info[cpu].core = -1; | ||
149 | continue; | ||
150 | } | ||
151 | if(sysfs_topology_read_file( | ||
152 | cpu, | ||
153 | "core_id", | ||
154 | &(cpu_top->core_info[cpu].core)) < 0) { | ||
155 | cpu_top->core_info[cpu].pkg = -1; | ||
156 | cpu_top->core_info[cpu].core = -1; | ||
157 | continue; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
162 | __compare); | ||
163 | |||
164 | /* Count the number of distinct pkgs values. This works | ||
165 | because the primary sort of the core_info struct was just | ||
166 | done by pkg value. */ | ||
167 | last_pkg = cpu_top->core_info[0].pkg; | ||
168 | for(cpu = 1; cpu < cpus; cpu++) { | ||
169 | if (cpu_top->core_info[cpu].pkg != last_pkg && | ||
170 | cpu_top->core_info[cpu].pkg != -1) { | ||
171 | |||
172 | last_pkg = cpu_top->core_info[cpu].pkg; | ||
173 | cpu_top->pkgs++; | ||
174 | } | ||
175 | } | ||
176 | if (!(cpu_top->core_info[0].pkg == -1)) | ||
177 | cpu_top->pkgs++; | ||
178 | |||
179 | /* Intel's cores count is not consecutively numbered, there may | ||
180 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
181 | * Get amount of cores by counting duplicates in a package | ||
182 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
183 | if (cpu_top->core_info[cpu].core == 0) | ||
184 | cpu_top->cores++; | ||
185 | */ | ||
186 | return cpus; | ||
187 | } | ||
188 | |||
189 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
190 | { | ||
191 | free(cpu_top.core_info); | ||
192 | } | ||
diff --git a/tools/power/cpupower/lib/cpupower.h b/tools/power/cpupower/lib/cpupower.h new file mode 100644 index 000000000000..fa031fcc7710 --- /dev/null +++ b/tools/power/cpupower/lib/cpupower.h | |||
@@ -0,0 +1,35 @@ | |||
1 | #ifndef __CPUPOWER_CPUPOWER_H__ | ||
2 | #define __CPUPOWER_CPUPOWER_H__ | ||
3 | |||
4 | struct cpupower_topology { | ||
5 | /* Amount of CPU cores, packages and threads per core in the system */ | ||
6 | unsigned int cores; | ||
7 | unsigned int pkgs; | ||
8 | unsigned int threads; /* per core */ | ||
9 | |||
10 | /* Array gets mallocated with cores entries, holding per core info */ | ||
11 | struct cpuid_core_info *core_info; | ||
12 | }; | ||
13 | |||
14 | struct cpuid_core_info { | ||
15 | int pkg; | ||
16 | int core; | ||
17 | int cpu; | ||
18 | |||
19 | /* flags */ | ||
20 | unsigned int is_online:1; | ||
21 | }; | ||
22 | |||
23 | #ifdef __cplusplus | ||
24 | extern "C" { | ||
25 | #endif | ||
26 | |||
27 | int get_cpu_topology(struct cpupower_topology *cpu_top); | ||
28 | void cpu_topology_release(struct cpupower_topology cpu_top); | ||
29 | int cpupower_is_cpu_online(unsigned int cpu); | ||
30 | |||
31 | #ifdef __cplusplus | ||
32 | } | ||
33 | #endif | ||
34 | |||
35 | #endif | ||
diff --git a/tools/power/cpupower/lib/cpupower_intern.h b/tools/power/cpupower/lib/cpupower_intern.h new file mode 100644 index 000000000000..f8ec4009621c --- /dev/null +++ b/tools/power/cpupower/lib/cpupower_intern.h | |||
@@ -0,0 +1,5 @@ | |||
1 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
2 | #define MAX_LINE_LEN 4096 | ||
3 | #define SYSFS_PATH_MAX 255 | ||
4 | |||
5 | unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | ||
diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c deleted file mode 100644 index 870713a75a81..000000000000 --- a/tools/power/cpupower/lib/sysfs.c +++ /dev/null | |||
@@ -1,672 +0,0 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <errno.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <limits.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "cpufreq.h" | ||
18 | |||
19 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
20 | #define MAX_LINE_LEN 4096 | ||
21 | #define SYSFS_PATH_MAX 255 | ||
22 | |||
23 | |||
24 | static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
25 | { | ||
26 | int fd; | ||
27 | ssize_t numread; | ||
28 | |||
29 | fd = open(path, O_RDONLY); | ||
30 | if (fd == -1) | ||
31 | return 0; | ||
32 | |||
33 | numread = read(fd, buf, buflen - 1); | ||
34 | if (numread < 1) { | ||
35 | close(fd); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | buf[numread] = '\0'; | ||
40 | close(fd); | ||
41 | |||
42 | return (unsigned int) numread; | ||
43 | } | ||
44 | |||
45 | |||
46 | /* CPUFREQ sysfs access **************************************************/ | ||
47 | |||
48 | /* helper function to read file from /sys into given buffer */ | ||
49 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
50 | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | ||
51 | char *buf, size_t buflen) | ||
52 | { | ||
53 | char path[SYSFS_PATH_MAX]; | ||
54 | |||
55 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
56 | cpu, fname); | ||
57 | return sysfs_read_file(path, buf, buflen); | ||
58 | } | ||
59 | |||
60 | /* helper function to write a new value to a /sys file */ | ||
61 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
62 | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | ||
63 | const char *fname, | ||
64 | const char *value, size_t len) | ||
65 | { | ||
66 | char path[SYSFS_PATH_MAX]; | ||
67 | int fd; | ||
68 | ssize_t numwrite; | ||
69 | |||
70 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
71 | cpu, fname); | ||
72 | |||
73 | fd = open(path, O_WRONLY); | ||
74 | if (fd == -1) | ||
75 | return 0; | ||
76 | |||
77 | numwrite = write(fd, value, len); | ||
78 | if (numwrite < 1) { | ||
79 | close(fd); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | close(fd); | ||
84 | |||
85 | return (unsigned int) numwrite; | ||
86 | } | ||
87 | |||
88 | /* read access to files which contain one numeric value */ | ||
89 | |||
90 | enum cpufreq_value { | ||
91 | CPUINFO_CUR_FREQ, | ||
92 | CPUINFO_MIN_FREQ, | ||
93 | CPUINFO_MAX_FREQ, | ||
94 | CPUINFO_LATENCY, | ||
95 | SCALING_CUR_FREQ, | ||
96 | SCALING_MIN_FREQ, | ||
97 | SCALING_MAX_FREQ, | ||
98 | STATS_NUM_TRANSITIONS, | ||
99 | MAX_CPUFREQ_VALUE_READ_FILES | ||
100 | }; | ||
101 | |||
102 | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | ||
103 | [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | ||
104 | [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | ||
105 | [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | ||
106 | [CPUINFO_LATENCY] = "cpuinfo_transition_latency", | ||
107 | [SCALING_CUR_FREQ] = "scaling_cur_freq", | ||
108 | [SCALING_MIN_FREQ] = "scaling_min_freq", | ||
109 | [SCALING_MAX_FREQ] = "scaling_max_freq", | ||
110 | [STATS_NUM_TRANSITIONS] = "stats/total_trans" | ||
111 | }; | ||
112 | |||
113 | |||
114 | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | ||
115 | enum cpufreq_value which) | ||
116 | { | ||
117 | unsigned long value; | ||
118 | unsigned int len; | ||
119 | char linebuf[MAX_LINE_LEN]; | ||
120 | char *endp; | ||
121 | |||
122 | if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | ||
123 | return 0; | ||
124 | |||
125 | len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | ||
126 | linebuf, sizeof(linebuf)); | ||
127 | |||
128 | if (len == 0) | ||
129 | return 0; | ||
130 | |||
131 | value = strtoul(linebuf, &endp, 0); | ||
132 | |||
133 | if (endp == linebuf || errno == ERANGE) | ||
134 | return 0; | ||
135 | |||
136 | return value; | ||
137 | } | ||
138 | |||
139 | /* read access to files which contain one string */ | ||
140 | |||
141 | enum cpufreq_string { | ||
142 | SCALING_DRIVER, | ||
143 | SCALING_GOVERNOR, | ||
144 | MAX_CPUFREQ_STRING_FILES | ||
145 | }; | ||
146 | |||
147 | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | ||
148 | [SCALING_DRIVER] = "scaling_driver", | ||
149 | [SCALING_GOVERNOR] = "scaling_governor", | ||
150 | }; | ||
151 | |||
152 | |||
153 | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | ||
154 | enum cpufreq_string which) | ||
155 | { | ||
156 | char linebuf[MAX_LINE_LEN]; | ||
157 | char *result; | ||
158 | unsigned int len; | ||
159 | |||
160 | if (which >= MAX_CPUFREQ_STRING_FILES) | ||
161 | return NULL; | ||
162 | |||
163 | len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | ||
164 | linebuf, sizeof(linebuf)); | ||
165 | if (len == 0) | ||
166 | return NULL; | ||
167 | |||
168 | result = strdup(linebuf); | ||
169 | if (result == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | if (result[strlen(result) - 1] == '\n') | ||
173 | result[strlen(result) - 1] = '\0'; | ||
174 | |||
175 | return result; | ||
176 | } | ||
177 | |||
178 | /* write access */ | ||
179 | |||
180 | enum cpufreq_write { | ||
181 | WRITE_SCALING_MIN_FREQ, | ||
182 | WRITE_SCALING_MAX_FREQ, | ||
183 | WRITE_SCALING_GOVERNOR, | ||
184 | WRITE_SCALING_SET_SPEED, | ||
185 | MAX_CPUFREQ_WRITE_FILES | ||
186 | }; | ||
187 | |||
188 | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | ||
189 | [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | ||
190 | [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | ||
191 | [WRITE_SCALING_GOVERNOR] = "scaling_governor", | ||
192 | [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | ||
193 | }; | ||
194 | |||
195 | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | ||
196 | enum cpufreq_write which, | ||
197 | const char *new_value, size_t len) | ||
198 | { | ||
199 | if (which >= MAX_CPUFREQ_WRITE_FILES) | ||
200 | return 0; | ||
201 | |||
202 | if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | ||
203 | new_value, len) != len) | ||
204 | return -ENODEV; | ||
205 | |||
206 | return 0; | ||
207 | }; | ||
208 | |||
209 | unsigned long sysfs_get_freq_kernel(unsigned int cpu) | ||
210 | { | ||
211 | return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); | ||
212 | } | ||
213 | |||
214 | unsigned long sysfs_get_freq_hardware(unsigned int cpu) | ||
215 | { | ||
216 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); | ||
217 | } | ||
218 | |||
219 | unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) | ||
220 | { | ||
221 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); | ||
222 | } | ||
223 | |||
224 | int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
225 | unsigned long *min, | ||
226 | unsigned long *max) | ||
227 | { | ||
228 | if ((!min) || (!max)) | ||
229 | return -EINVAL; | ||
230 | |||
231 | *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | ||
232 | if (!*min) | ||
233 | return -ENODEV; | ||
234 | |||
235 | *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | ||
236 | if (!*max) | ||
237 | return -ENODEV; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | char *sysfs_get_freq_driver(unsigned int cpu) | ||
243 | { | ||
244 | return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); | ||
245 | } | ||
246 | |||
247 | struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) | ||
248 | { | ||
249 | struct cpufreq_policy *policy; | ||
250 | |||
251 | policy = malloc(sizeof(struct cpufreq_policy)); | ||
252 | if (!policy) | ||
253 | return NULL; | ||
254 | |||
255 | policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | ||
256 | if (!policy->governor) { | ||
257 | free(policy); | ||
258 | return NULL; | ||
259 | } | ||
260 | policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
261 | policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | ||
262 | if ((!policy->min) || (!policy->max)) { | ||
263 | free(policy->governor); | ||
264 | free(policy); | ||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | return policy; | ||
269 | } | ||
270 | |||
271 | struct cpufreq_available_governors * | ||
272 | sysfs_get_freq_available_governors(unsigned int cpu) { | ||
273 | struct cpufreq_available_governors *first = NULL; | ||
274 | struct cpufreq_available_governors *current = NULL; | ||
275 | char linebuf[MAX_LINE_LEN]; | ||
276 | unsigned int pos, i; | ||
277 | unsigned int len; | ||
278 | |||
279 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | ||
280 | linebuf, sizeof(linebuf)); | ||
281 | if (len == 0) | ||
282 | return NULL; | ||
283 | |||
284 | pos = 0; | ||
285 | for (i = 0; i < len; i++) { | ||
286 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
287 | if (i - pos < 2) | ||
288 | continue; | ||
289 | if (current) { | ||
290 | current->next = malloc(sizeof(*current)); | ||
291 | if (!current->next) | ||
292 | goto error_out; | ||
293 | current = current->next; | ||
294 | } else { | ||
295 | first = malloc(sizeof(*first)); | ||
296 | if (!first) | ||
297 | goto error_out; | ||
298 | current = first; | ||
299 | } | ||
300 | current->first = first; | ||
301 | current->next = NULL; | ||
302 | |||
303 | current->governor = malloc(i - pos + 1); | ||
304 | if (!current->governor) | ||
305 | goto error_out; | ||
306 | |||
307 | memcpy(current->governor, linebuf + pos, i - pos); | ||
308 | current->governor[i - pos] = '\0'; | ||
309 | pos = i + 1; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | return first; | ||
314 | |||
315 | error_out: | ||
316 | while (first) { | ||
317 | current = first->next; | ||
318 | if (first->governor) | ||
319 | free(first->governor); | ||
320 | free(first); | ||
321 | first = current; | ||
322 | } | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | |||
327 | struct cpufreq_available_frequencies * | ||
328 | sysfs_get_available_frequencies(unsigned int cpu) { | ||
329 | struct cpufreq_available_frequencies *first = NULL; | ||
330 | struct cpufreq_available_frequencies *current = NULL; | ||
331 | char one_value[SYSFS_PATH_MAX]; | ||
332 | char linebuf[MAX_LINE_LEN]; | ||
333 | unsigned int pos, i; | ||
334 | unsigned int len; | ||
335 | |||
336 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | ||
337 | linebuf, sizeof(linebuf)); | ||
338 | if (len == 0) | ||
339 | return NULL; | ||
340 | |||
341 | pos = 0; | ||
342 | for (i = 0; i < len; i++) { | ||
343 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
344 | if (i - pos < 2) | ||
345 | continue; | ||
346 | if (i - pos >= SYSFS_PATH_MAX) | ||
347 | goto error_out; | ||
348 | if (current) { | ||
349 | current->next = malloc(sizeof(*current)); | ||
350 | if (!current->next) | ||
351 | goto error_out; | ||
352 | current = current->next; | ||
353 | } else { | ||
354 | first = malloc(sizeof(*first)); | ||
355 | if (!first) | ||
356 | goto error_out; | ||
357 | current = first; | ||
358 | } | ||
359 | current->first = first; | ||
360 | current->next = NULL; | ||
361 | |||
362 | memcpy(one_value, linebuf + pos, i - pos); | ||
363 | one_value[i - pos] = '\0'; | ||
364 | if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | ||
365 | goto error_out; | ||
366 | |||
367 | pos = i + 1; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | return first; | ||
372 | |||
373 | error_out: | ||
374 | while (first) { | ||
375 | current = first->next; | ||
376 | free(first); | ||
377 | first = current; | ||
378 | } | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | ||
383 | const char *file) | ||
384 | { | ||
385 | struct cpufreq_affected_cpus *first = NULL; | ||
386 | struct cpufreq_affected_cpus *current = NULL; | ||
387 | char one_value[SYSFS_PATH_MAX]; | ||
388 | char linebuf[MAX_LINE_LEN]; | ||
389 | unsigned int pos, i; | ||
390 | unsigned int len; | ||
391 | |||
392 | len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | ||
393 | if (len == 0) | ||
394 | return NULL; | ||
395 | |||
396 | pos = 0; | ||
397 | for (i = 0; i < len; i++) { | ||
398 | if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
399 | if (i - pos < 1) | ||
400 | continue; | ||
401 | if (i - pos >= SYSFS_PATH_MAX) | ||
402 | goto error_out; | ||
403 | if (current) { | ||
404 | current->next = malloc(sizeof(*current)); | ||
405 | if (!current->next) | ||
406 | goto error_out; | ||
407 | current = current->next; | ||
408 | } else { | ||
409 | first = malloc(sizeof(*first)); | ||
410 | if (!first) | ||
411 | goto error_out; | ||
412 | current = first; | ||
413 | } | ||
414 | current->first = first; | ||
415 | current->next = NULL; | ||
416 | |||
417 | memcpy(one_value, linebuf + pos, i - pos); | ||
418 | one_value[i - pos] = '\0'; | ||
419 | |||
420 | if (sscanf(one_value, "%u", ¤t->cpu) != 1) | ||
421 | goto error_out; | ||
422 | |||
423 | pos = i + 1; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | return first; | ||
428 | |||
429 | error_out: | ||
430 | while (first) { | ||
431 | current = first->next; | ||
432 | free(first); | ||
433 | first = current; | ||
434 | } | ||
435 | return NULL; | ||
436 | } | ||
437 | |||
438 | struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) | ||
439 | { | ||
440 | return sysfs_get_cpu_list(cpu, "affected_cpus"); | ||
441 | } | ||
442 | |||
443 | struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) | ||
444 | { | ||
445 | return sysfs_get_cpu_list(cpu, "related_cpus"); | ||
446 | } | ||
447 | |||
448 | struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
449 | unsigned long long *total_time) { | ||
450 | struct cpufreq_stats *first = NULL; | ||
451 | struct cpufreq_stats *current = NULL; | ||
452 | char one_value[SYSFS_PATH_MAX]; | ||
453 | char linebuf[MAX_LINE_LEN]; | ||
454 | unsigned int pos, i; | ||
455 | unsigned int len; | ||
456 | |||
457 | len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | ||
458 | linebuf, sizeof(linebuf)); | ||
459 | if (len == 0) | ||
460 | return NULL; | ||
461 | |||
462 | *total_time = 0; | ||
463 | pos = 0; | ||
464 | for (i = 0; i < len; i++) { | ||
465 | if (i == strlen(linebuf) || linebuf[i] == '\n') { | ||
466 | if (i - pos < 2) | ||
467 | continue; | ||
468 | if ((i - pos) >= SYSFS_PATH_MAX) | ||
469 | goto error_out; | ||
470 | if (current) { | ||
471 | current->next = malloc(sizeof(*current)); | ||
472 | if (!current->next) | ||
473 | goto error_out; | ||
474 | current = current->next; | ||
475 | } else { | ||
476 | first = malloc(sizeof(*first)); | ||
477 | if (!first) | ||
478 | goto error_out; | ||
479 | current = first; | ||
480 | } | ||
481 | current->first = first; | ||
482 | current->next = NULL; | ||
483 | |||
484 | memcpy(one_value, linebuf + pos, i - pos); | ||
485 | one_value[i - pos] = '\0'; | ||
486 | if (sscanf(one_value, "%lu %llu", | ||
487 | ¤t->frequency, | ||
488 | ¤t->time_in_state) != 2) | ||
489 | goto error_out; | ||
490 | |||
491 | *total_time = *total_time + current->time_in_state; | ||
492 | pos = i + 1; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | return first; | ||
497 | |||
498 | error_out: | ||
499 | while (first) { | ||
500 | current = first->next; | ||
501 | free(first); | ||
502 | first = current; | ||
503 | } | ||
504 | return NULL; | ||
505 | } | ||
506 | |||
507 | unsigned long sysfs_get_freq_transitions(unsigned int cpu) | ||
508 | { | ||
509 | return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); | ||
510 | } | ||
511 | |||
512 | static int verify_gov(char *new_gov, char *passed_gov) | ||
513 | { | ||
514 | unsigned int i, j = 0; | ||
515 | |||
516 | if (!passed_gov || (strlen(passed_gov) > 19)) | ||
517 | return -EINVAL; | ||
518 | |||
519 | strncpy(new_gov, passed_gov, 20); | ||
520 | for (i = 0; i < 20; i++) { | ||
521 | if (j) { | ||
522 | new_gov[i] = '\0'; | ||
523 | continue; | ||
524 | } | ||
525 | if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | ||
526 | continue; | ||
527 | |||
528 | if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | ||
529 | continue; | ||
530 | |||
531 | if (new_gov[i] == '-') | ||
532 | continue; | ||
533 | |||
534 | if (new_gov[i] == '_') | ||
535 | continue; | ||
536 | |||
537 | if (new_gov[i] == '\0') { | ||
538 | j = 1; | ||
539 | continue; | ||
540 | } | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | new_gov[19] = '\0'; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) | ||
548 | { | ||
549 | char new_gov[SYSFS_PATH_MAX]; | ||
550 | |||
551 | if (!governor) | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (verify_gov(new_gov, governor)) | ||
555 | return -EINVAL; | ||
556 | |||
557 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
558 | new_gov, strlen(new_gov)); | ||
559 | }; | ||
560 | |||
561 | int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) | ||
562 | { | ||
563 | char value[SYSFS_PATH_MAX]; | ||
564 | |||
565 | snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | ||
566 | |||
567 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
568 | value, strlen(value)); | ||
569 | }; | ||
570 | |||
571 | |||
572 | int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) | ||
573 | { | ||
574 | char value[SYSFS_PATH_MAX]; | ||
575 | |||
576 | snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | ||
577 | |||
578 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | ||
579 | value, strlen(value)); | ||
580 | }; | ||
581 | |||
582 | |||
583 | int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) | ||
584 | { | ||
585 | char min[SYSFS_PATH_MAX]; | ||
586 | char max[SYSFS_PATH_MAX]; | ||
587 | char gov[SYSFS_PATH_MAX]; | ||
588 | int ret; | ||
589 | unsigned long old_min; | ||
590 | int write_max_first; | ||
591 | |||
592 | if (!policy || !(policy->governor)) | ||
593 | return -EINVAL; | ||
594 | |||
595 | if (policy->max < policy->min) | ||
596 | return -EINVAL; | ||
597 | |||
598 | if (verify_gov(gov, policy->governor)) | ||
599 | return -EINVAL; | ||
600 | |||
601 | snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | ||
602 | snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | ||
603 | |||
604 | old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
605 | write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | ||
606 | |||
607 | if (write_max_first) { | ||
608 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
609 | max, strlen(max)); | ||
610 | if (ret) | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | ||
615 | strlen(min)); | ||
616 | if (ret) | ||
617 | return ret; | ||
618 | |||
619 | if (!write_max_first) { | ||
620 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
621 | max, strlen(max)); | ||
622 | if (ret) | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
627 | gov, strlen(gov)); | ||
628 | } | ||
629 | |||
630 | int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) | ||
631 | { | ||
632 | struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); | ||
633 | char userspace_gov[] = "userspace"; | ||
634 | char freq[SYSFS_PATH_MAX]; | ||
635 | int ret; | ||
636 | |||
637 | if (!pol) | ||
638 | return -ENODEV; | ||
639 | |||
640 | if (strncmp(pol->governor, userspace_gov, 9) != 0) { | ||
641 | ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); | ||
642 | if (ret) { | ||
643 | cpufreq_put_policy(pol); | ||
644 | return ret; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | cpufreq_put_policy(pol); | ||
649 | |||
650 | snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | ||
651 | |||
652 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | ||
653 | freq, strlen(freq)); | ||
654 | } | ||
655 | |||
656 | /* CPUFREQ sysfs access **************************************************/ | ||
657 | |||
658 | /* General sysfs access **************************************************/ | ||
659 | int sysfs_cpu_exists(unsigned int cpu) | ||
660 | { | ||
661 | char file[SYSFS_PATH_MAX]; | ||
662 | struct stat statbuf; | ||
663 | |||
664 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); | ||
665 | |||
666 | if (stat(file, &statbuf) != 0) | ||
667 | return -ENOSYS; | ||
668 | |||
669 | return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; | ||
670 | } | ||
671 | |||
672 | /* General sysfs access **************************************************/ | ||
diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h deleted file mode 100644 index c76a5e0af501..000000000000 --- a/tools/power/cpupower/lib/sysfs.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* General */ | ||
2 | extern unsigned int sysfs_cpu_exists(unsigned int cpu); | ||
3 | |||
4 | /* CPUfreq */ | ||
5 | extern unsigned long sysfs_get_freq_kernel(unsigned int cpu); | ||
6 | extern unsigned long sysfs_get_freq_hardware(unsigned int cpu); | ||
7 | extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu); | ||
8 | extern int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
9 | unsigned long *min, unsigned long *max); | ||
10 | extern char *sysfs_get_freq_driver(unsigned int cpu); | ||
11 | extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu); | ||
12 | extern struct cpufreq_available_governors *sysfs_get_freq_available_governors( | ||
13 | unsigned int cpu); | ||
14 | extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies( | ||
15 | unsigned int cpu); | ||
16 | extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus( | ||
17 | unsigned int cpu); | ||
18 | extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus( | ||
19 | unsigned int cpu); | ||
20 | extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
21 | unsigned long long *total_time); | ||
22 | extern unsigned long sysfs_get_freq_transitions(unsigned int cpu); | ||
23 | extern int sysfs_set_freq_policy(unsigned int cpu, | ||
24 | struct cpufreq_policy *policy); | ||
25 | extern int sysfs_modify_freq_policy_min(unsigned int cpu, | ||
26 | unsigned long min_freq); | ||
27 | extern int sysfs_modify_freq_policy_max(unsigned int cpu, | ||
28 | unsigned long max_freq); | ||
29 | extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor); | ||
30 | extern int sysfs_set_frequency(unsigned int cpu, | ||
31 | unsigned long target_frequency); | ||
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index 9c85a382e355..6aa8d239dff9 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information | 4 | cpupower\-frequency\-info \- Utility to retrieve cpufreq kernel information |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 index 3eacc8d03d1a..b50570221a5b 100644 --- a/tools/power/cpupower/man/cpupower-frequency-set.1 +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. | 4 | cpupower\-frequency\-set \- A small tool which allows to modify cpufreq settings. |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] | 7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 index 7b3646adb92f..80a1311fa747 100644 --- a/tools/power/cpupower/man/cpupower-idle-info.1 +++ b/tools/power/cpupower/man/cpupower-idle-info.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower idle\-info \- Utility to retrieve cpu idle kernel information | 4 | cpupower\-idle\-info \- Utility to retrieve cpu idle kernel information |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1 index 580c4e3ea92a..21916cff7516 100644 --- a/tools/power/cpupower/man/cpupower-idle-set.1 +++ b/tools/power/cpupower/man/cpupower-idle-set.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower idle\-set \- Utility to set cpu idle state specific kernel options | 4 | cpupower\-idle\-set \- Utility to set cpu idle state specific kernel options |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 0fbd1a22c0a9..b4bf76971dc9 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -16,8 +16,8 @@ | |||
16 | #include <getopt.h> | 16 | #include <getopt.h> |
17 | 17 | ||
18 | #include "cpufreq.h" | 18 | #include "cpufreq.h" |
19 | #include "cpuidle.h" | ||
19 | #include "helpers/helpers.h" | 20 | #include "helpers/helpers.h" |
20 | #include "helpers/sysfs.h" | ||
21 | 21 | ||
22 | #define NORM_FREQ_LEN 32 | 22 | #define NORM_FREQ_LEN 32 |
23 | 23 | ||
@@ -296,7 +296,7 @@ int cmd_freq_set(int argc, char **argv) | |||
296 | struct cpufreq_affected_cpus *cpus; | 296 | struct cpufreq_affected_cpus *cpus; |
297 | 297 | ||
298 | if (!bitmask_isbitset(cpus_chosen, cpu) || | 298 | if (!bitmask_isbitset(cpus_chosen, cpu) || |
299 | cpufreq_cpu_exists(cpu)) | 299 | cpupower_is_cpu_online(cpu)) |
300 | continue; | 300 | continue; |
301 | 301 | ||
302 | cpus = cpufreq_get_related_cpus(cpu); | 302 | cpus = cpufreq_get_related_cpus(cpu); |
@@ -316,10 +316,10 @@ int cmd_freq_set(int argc, char **argv) | |||
316 | cpu <= bitmask_last(cpus_chosen); cpu++) { | 316 | cpu <= bitmask_last(cpus_chosen); cpu++) { |
317 | 317 | ||
318 | if (!bitmask_isbitset(cpus_chosen, cpu) || | 318 | if (!bitmask_isbitset(cpus_chosen, cpu) || |
319 | cpufreq_cpu_exists(cpu)) | 319 | cpupower_is_cpu_online(cpu)) |
320 | continue; | 320 | continue; |
321 | 321 | ||
322 | if (sysfs_is_cpu_online(cpu) != 1) | 322 | if (cpupower_is_cpu_online(cpu) != 1) |
323 | continue; | 323 | continue; |
324 | 324 | ||
325 | printf(_("Setting cpu: %d\n"), cpu); | 325 | printf(_("Setting cpu: %d\n"), cpu); |
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 8bf8ab5ffa25..b59c85defa05 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -13,8 +13,10 @@ | |||
13 | #include <string.h> | 13 | #include <string.h> |
14 | #include <getopt.h> | 14 | #include <getopt.h> |
15 | 15 | ||
16 | #include "helpers/helpers.h" | 16 | #include <cpuidle.h> |
17 | |||
17 | #include "helpers/sysfs.h" | 18 | #include "helpers/sysfs.h" |
19 | #include "helpers/helpers.h" | ||
18 | #include "helpers/bitmask.h" | 20 | #include "helpers/bitmask.h" |
19 | 21 | ||
20 | #define LINE_LEN 10 | 22 | #define LINE_LEN 10 |
@@ -24,7 +26,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
24 | unsigned int idlestates, idlestate; | 26 | unsigned int idlestates, idlestate; |
25 | char *tmp; | 27 | char *tmp; |
26 | 28 | ||
27 | idlestates = sysfs_get_idlestate_count(cpu); | 29 | idlestates = cpuidle_state_count(cpu); |
28 | if (idlestates == 0) { | 30 | if (idlestates == 0) { |
29 | printf(_("CPU %u: No idle states\n"), cpu); | 31 | printf(_("CPU %u: No idle states\n"), cpu); |
30 | return; | 32 | return; |
@@ -33,7 +35,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
33 | printf(_("Number of idle states: %d\n"), idlestates); | 35 | printf(_("Number of idle states: %d\n"), idlestates); |
34 | printf(_("Available idle states:")); | 36 | printf(_("Available idle states:")); |
35 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 37 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
36 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 38 | tmp = cpuidle_state_name(cpu, idlestate); |
37 | if (!tmp) | 39 | if (!tmp) |
38 | continue; | 40 | continue; |
39 | printf(" %s", tmp); | 41 | printf(" %s", tmp); |
@@ -45,28 +47,28 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
45 | return; | 47 | return; |
46 | 48 | ||
47 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 49 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
48 | int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); | 50 | int disabled = cpuidle_is_state_disabled(cpu, idlestate); |
49 | /* Disabled interface not supported on older kernels */ | 51 | /* Disabled interface not supported on older kernels */ |
50 | if (disabled < 0) | 52 | if (disabled < 0) |
51 | disabled = 0; | 53 | disabled = 0; |
52 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 54 | tmp = cpuidle_state_name(cpu, idlestate); |
53 | if (!tmp) | 55 | if (!tmp) |
54 | continue; | 56 | continue; |
55 | printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); | 57 | printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); |
56 | free(tmp); | 58 | free(tmp); |
57 | 59 | ||
58 | tmp = sysfs_get_idlestate_desc(cpu, idlestate); | 60 | tmp = cpuidle_state_desc(cpu, idlestate); |
59 | if (!tmp) | 61 | if (!tmp) |
60 | continue; | 62 | continue; |
61 | printf(_("Flags/Description: %s\n"), tmp); | 63 | printf(_("Flags/Description: %s\n"), tmp); |
62 | free(tmp); | 64 | free(tmp); |
63 | 65 | ||
64 | printf(_("Latency: %lu\n"), | 66 | printf(_("Latency: %lu\n"), |
65 | sysfs_get_idlestate_latency(cpu, idlestate)); | 67 | cpuidle_state_latency(cpu, idlestate)); |
66 | printf(_("Usage: %lu\n"), | 68 | printf(_("Usage: %lu\n"), |
67 | sysfs_get_idlestate_usage(cpu, idlestate)); | 69 | cpuidle_state_usage(cpu, idlestate)); |
68 | printf(_("Duration: %llu\n"), | 70 | printf(_("Duration: %llu\n"), |
69 | sysfs_get_idlestate_time(cpu, idlestate)); | 71 | cpuidle_state_time(cpu, idlestate)); |
70 | } | 72 | } |
71 | } | 73 | } |
72 | 74 | ||
@@ -74,7 +76,7 @@ static void cpuidle_general_output(void) | |||
74 | { | 76 | { |
75 | char *tmp; | 77 | char *tmp; |
76 | 78 | ||
77 | tmp = sysfs_get_cpuidle_driver(); | 79 | tmp = cpuidle_get_driver(); |
78 | if (!tmp) { | 80 | if (!tmp) { |
79 | printf(_("Could not determine cpuidle driver\n")); | 81 | printf(_("Could not determine cpuidle driver\n")); |
80 | return; | 82 | return; |
@@ -83,7 +85,7 @@ static void cpuidle_general_output(void) | |||
83 | printf(_("CPUidle driver: %s\n"), tmp); | 85 | printf(_("CPUidle driver: %s\n"), tmp); |
84 | free(tmp); | 86 | free(tmp); |
85 | 87 | ||
86 | tmp = sysfs_get_cpuidle_governor(); | 88 | tmp = cpuidle_get_governor(); |
87 | if (!tmp) { | 89 | if (!tmp) { |
88 | printf(_("Could not determine cpuidle governor\n")); | 90 | printf(_("Could not determine cpuidle governor\n")); |
89 | return; | 91 | return; |
@@ -98,7 +100,7 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
98 | long max_allowed_cstate = 2000000000; | 100 | long max_allowed_cstate = 2000000000; |
99 | unsigned int cstate, cstates; | 101 | unsigned int cstate, cstates; |
100 | 102 | ||
101 | cstates = sysfs_get_idlestate_count(cpu); | 103 | cstates = cpuidle_state_count(cpu); |
102 | if (cstates == 0) { | 104 | if (cstates == 0) { |
103 | printf(_("CPU %u: No C-states info\n"), cpu); | 105 | printf(_("CPU %u: No C-states info\n"), cpu); |
104 | return; | 106 | return; |
@@ -113,11 +115,11 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
113 | "type[C%d] "), cstate, cstate); | 115 | "type[C%d] "), cstate, cstate); |
114 | printf(_("promotion[--] demotion[--] ")); | 116 | printf(_("promotion[--] demotion[--] ")); |
115 | printf(_("latency[%03lu] "), | 117 | printf(_("latency[%03lu] "), |
116 | sysfs_get_idlestate_latency(cpu, cstate)); | 118 | cpuidle_state_latency(cpu, cstate)); |
117 | printf(_("usage[%08lu] "), | 119 | printf(_("usage[%08lu] "), |
118 | sysfs_get_idlestate_usage(cpu, cstate)); | 120 | cpuidle_state_usage(cpu, cstate)); |
119 | printf(_("duration[%020Lu] \n"), | 121 | printf(_("duration[%020Lu] \n"), |
120 | sysfs_get_idlestate_time(cpu, cstate)); | 122 | cpuidle_state_time(cpu, cstate)); |
121 | } | 123 | } |
122 | } | 124 | } |
123 | 125 | ||
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c index d6b6ae44b8c2..691c24d50ef4 100644 --- a/tools/power/cpupower/utils/cpuidle-set.c +++ b/tools/power/cpupower/utils/cpuidle-set.c | |||
@@ -5,12 +5,12 @@ | |||
5 | #include <limits.h> | 5 | #include <limits.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <ctype.h> | 7 | #include <ctype.h> |
8 | |||
9 | #include <getopt.h> | 8 | #include <getopt.h> |
10 | 9 | ||
11 | #include "cpufreq.h" | 10 | #include <cpufreq.h> |
11 | #include <cpuidle.h> | ||
12 | |||
12 | #include "helpers/helpers.h" | 13 | #include "helpers/helpers.h" |
13 | #include "helpers/sysfs.h" | ||
14 | 14 | ||
15 | static struct option info_opts[] = { | 15 | static struct option info_opts[] = { |
16 | {"disable", required_argument, NULL, 'd'}, | 16 | {"disable", required_argument, NULL, 'd'}, |
@@ -104,16 +104,16 @@ int cmd_idle_set(int argc, char **argv) | |||
104 | if (!bitmask_isbitset(cpus_chosen, cpu)) | 104 | if (!bitmask_isbitset(cpus_chosen, cpu)) |
105 | continue; | 105 | continue; |
106 | 106 | ||
107 | if (sysfs_is_cpu_online(cpu) != 1) | 107 | if (cpupower_is_cpu_online(cpu) != 1) |
108 | continue; | 108 | continue; |
109 | 109 | ||
110 | idlestates = sysfs_get_idlestate_count(cpu); | 110 | idlestates = cpuidle_state_count(cpu); |
111 | if (idlestates <= 0) | 111 | if (idlestates <= 0) |
112 | continue; | 112 | continue; |
113 | 113 | ||
114 | switch (param) { | 114 | switch (param) { |
115 | case 'd': | 115 | case 'd': |
116 | ret = sysfs_idlestate_disable(cpu, idlestate, 1); | 116 | ret = cpuidle_state_disable(cpu, idlestate, 1); |
117 | if (ret == 0) | 117 | if (ret == 0) |
118 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); | 118 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); |
119 | else if (ret == -1) | 119 | else if (ret == -1) |
@@ -126,7 +126,7 @@ int cmd_idle_set(int argc, char **argv) | |||
126 | idlestate, cpu); | 126 | idlestate, cpu); |
127 | break; | 127 | break; |
128 | case 'e': | 128 | case 'e': |
129 | ret = sysfs_idlestate_disable(cpu, idlestate, 0); | 129 | ret = cpuidle_state_disable(cpu, idlestate, 0); |
130 | if (ret == 0) | 130 | if (ret == 0) |
131 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 131 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
132 | else if (ret == -1) | 132 | else if (ret == -1) |
@@ -140,13 +140,13 @@ int cmd_idle_set(int argc, char **argv) | |||
140 | break; | 140 | break; |
141 | case 'D': | 141 | case 'D': |
142 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 142 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
143 | disabled = sysfs_is_idlestate_disabled | 143 | disabled = cpuidle_is_state_disabled |
144 | (cpu, idlestate); | 144 | (cpu, idlestate); |
145 | state_latency = sysfs_get_idlestate_latency | 145 | state_latency = cpuidle_state_latency |
146 | (cpu, idlestate); | 146 | (cpu, idlestate); |
147 | if (disabled == 1) { | 147 | if (disabled == 1) { |
148 | if (latency > state_latency){ | 148 | if (latency > state_latency){ |
149 | ret = sysfs_idlestate_disable | 149 | ret = cpuidle_state_disable |
150 | (cpu, idlestate, 0); | 150 | (cpu, idlestate, 0); |
151 | if (ret == 0) | 151 | if (ret == 0) |
152 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 152 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
@@ -154,7 +154,7 @@ int cmd_idle_set(int argc, char **argv) | |||
154 | continue; | 154 | continue; |
155 | } | 155 | } |
156 | if (latency <= state_latency){ | 156 | if (latency <= state_latency){ |
157 | ret = sysfs_idlestate_disable | 157 | ret = cpuidle_state_disable |
158 | (cpu, idlestate, 1); | 158 | (cpu, idlestate, 1); |
159 | if (ret == 0) | 159 | if (ret == 0) |
160 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); | 160 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); |
@@ -163,10 +163,10 @@ int cmd_idle_set(int argc, char **argv) | |||
163 | break; | 163 | break; |
164 | case 'E': | 164 | case 'E': |
165 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 165 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
166 | disabled = sysfs_is_idlestate_disabled | 166 | disabled = cpuidle_is_state_disabled |
167 | (cpu, idlestate); | 167 | (cpu, idlestate); |
168 | if (disabled == 1) { | 168 | if (disabled == 1) { |
169 | ret = sysfs_idlestate_disable | 169 | ret = cpuidle_state_disable |
170 | (cpu, idlestate, 0); | 170 | (cpu, idlestate, 0); |
171 | if (ret == 0) | 171 | if (ret == 0) |
172 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 172 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index aa9e95486a2d..afb66f80554e 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <locale.h> | 14 | #include <locale.h> |
15 | 15 | ||
16 | #include "helpers/bitmask.h" | 16 | #include "helpers/bitmask.h" |
17 | #include <cpupower.h> | ||
17 | 18 | ||
18 | /* Internationalization ****************************/ | 19 | /* Internationalization ****************************/ |
19 | #ifdef NLS | 20 | #ifdef NLS |
@@ -92,31 +93,6 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); | |||
92 | extern struct cpupower_cpu_info cpupower_cpu_info; | 93 | extern struct cpupower_cpu_info cpupower_cpu_info; |
93 | /* cpuid and cpuinfo helpers **************************/ | 94 | /* cpuid and cpuinfo helpers **************************/ |
94 | 95 | ||
95 | struct cpuid_core_info { | ||
96 | int pkg; | ||
97 | int core; | ||
98 | int cpu; | ||
99 | |||
100 | /* flags */ | ||
101 | unsigned int is_online:1; | ||
102 | }; | ||
103 | |||
104 | /* CPU topology/hierarchy parsing ******************/ | ||
105 | struct cpupower_topology { | ||
106 | /* Amount of CPU cores, packages and threads per core in the system */ | ||
107 | unsigned int cores; | ||
108 | unsigned int pkgs; | ||
109 | unsigned int threads; /* per core */ | ||
110 | |||
111 | /* Array gets mallocated with cores entries, holding per core info */ | ||
112 | struct cpuid_core_info *core_info; | ||
113 | }; | ||
114 | |||
115 | extern int get_cpu_topology(struct cpupower_topology *cpu_top); | ||
116 | extern void cpu_topology_release(struct cpupower_topology cpu_top); | ||
117 | |||
118 | /* CPU topology/hierarchy parsing ******************/ | ||
119 | |||
120 | /* X86 ONLY ****************************************/ | 96 | /* X86 ONLY ****************************************/ |
121 | #if defined(__i386__) || defined(__x86_64__) | 97 | #if defined(__i386__) || defined(__x86_64__) |
122 | 98 | ||
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 5f9c908f4557..a1a6c6041a1e 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -16,110 +16,7 @@ | |||
16 | #include <errno.h> | 16 | #include <errno.h> |
17 | #include <fcntl.h> | 17 | #include <fcntl.h> |
18 | 18 | ||
19 | #include <helpers/helpers.h> | 19 | #include <cpuidle.h> |
20 | #include <helpers/sysfs.h> | ||
21 | 20 | ||
22 | /* returns -1 on failure, 0 on success */ | 21 | /* CPU topology/hierarchy parsing ******************/ |
23 | static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) | ||
24 | { | ||
25 | char linebuf[MAX_LINE_LEN]; | ||
26 | char *endp; | ||
27 | char path[SYSFS_PATH_MAX]; | ||
28 | 22 | ||
29 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
30 | cpu, fname); | ||
31 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
32 | return -1; | ||
33 | *result = strtol(linebuf, &endp, 0); | ||
34 | if (endp == linebuf || errno == ERANGE) | ||
35 | return -1; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int __compare(const void *t1, const void *t2) | ||
40 | { | ||
41 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
42 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
43 | if (top1->pkg < top2->pkg) | ||
44 | return -1; | ||
45 | else if (top1->pkg > top2->pkg) | ||
46 | return 1; | ||
47 | else if (top1->core < top2->core) | ||
48 | return -1; | ||
49 | else if (top1->core > top2->core) | ||
50 | return 1; | ||
51 | else if (top1->cpu < top2->cpu) | ||
52 | return -1; | ||
53 | else if (top1->cpu > top2->cpu) | ||
54 | return 1; | ||
55 | else | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Returns amount of cpus, negative on error, cpu_top must be | ||
61 | * passed to cpu_topology_release to free resources | ||
62 | * | ||
63 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
64 | */ | ||
65 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
66 | { | ||
67 | int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
68 | |||
69 | cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); | ||
70 | if (cpu_top->core_info == NULL) | ||
71 | return -ENOMEM; | ||
72 | cpu_top->pkgs = cpu_top->cores = 0; | ||
73 | for (cpu = 0; cpu < cpus; cpu++) { | ||
74 | cpu_top->core_info[cpu].cpu = cpu; | ||
75 | cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); | ||
76 | if(sysfs_topology_read_file( | ||
77 | cpu, | ||
78 | "physical_package_id", | ||
79 | &(cpu_top->core_info[cpu].pkg)) < 0) { | ||
80 | cpu_top->core_info[cpu].pkg = -1; | ||
81 | cpu_top->core_info[cpu].core = -1; | ||
82 | continue; | ||
83 | } | ||
84 | if(sysfs_topology_read_file( | ||
85 | cpu, | ||
86 | "core_id", | ||
87 | &(cpu_top->core_info[cpu].core)) < 0) { | ||
88 | cpu_top->core_info[cpu].pkg = -1; | ||
89 | cpu_top->core_info[cpu].core = -1; | ||
90 | continue; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
95 | __compare); | ||
96 | |||
97 | /* Count the number of distinct pkgs values. This works | ||
98 | because the primary sort of the core_info struct was just | ||
99 | done by pkg value. */ | ||
100 | last_pkg = cpu_top->core_info[0].pkg; | ||
101 | for(cpu = 1; cpu < cpus; cpu++) { | ||
102 | if (cpu_top->core_info[cpu].pkg != last_pkg && | ||
103 | cpu_top->core_info[cpu].pkg != -1) { | ||
104 | |||
105 | last_pkg = cpu_top->core_info[cpu].pkg; | ||
106 | cpu_top->pkgs++; | ||
107 | } | ||
108 | } | ||
109 | if (!(cpu_top->core_info[0].pkg == -1)) | ||
110 | cpu_top->pkgs++; | ||
111 | |||
112 | /* Intel's cores count is not consecutively numbered, there may | ||
113 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
114 | * Get amount of cores by counting duplicates in a package | ||
115 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
116 | if (cpu_top->core_info[cpu].core == 0) | ||
117 | cpu_top->cores++; | ||
118 | */ | ||
119 | return cpus; | ||
120 | } | ||
121 | |||
122 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
123 | { | ||
124 | free(cpu_top.core_info); | ||
125 | } | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index bcd22a1a3970..1b5da0066ebf 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -10,8 +10,8 @@ | |||
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <limits.h> | 12 | #include <limits.h> |
13 | #include <cpuidle.h> | ||
13 | 14 | ||
14 | #include "helpers/sysfs.h" | ||
15 | #include "helpers/helpers.h" | 15 | #include "helpers/helpers.h" |
16 | #include "idle_monitor/cpupower-monitor.h" | 16 | #include "idle_monitor/cpupower-monitor.h" |
17 | 17 | ||
@@ -51,7 +51,7 @@ static int cpuidle_start(void) | |||
51 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | 51 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; |
52 | state++) { | 52 | state++) { |
53 | previous_count[cpu][state] = | 53 | previous_count[cpu][state] = |
54 | sysfs_get_idlestate_time(cpu, state); | 54 | cpuidle_state_time(cpu, state); |
55 | dprint("CPU %d - State: %d - Val: %llu\n", | 55 | dprint("CPU %d - State: %d - Val: %llu\n", |
56 | cpu, state, previous_count[cpu][state]); | 56 | cpu, state, previous_count[cpu][state]); |
57 | } | 57 | } |
@@ -70,7 +70,7 @@ static int cpuidle_stop(void) | |||
70 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | 70 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; |
71 | state++) { | 71 | state++) { |
72 | current_count[cpu][state] = | 72 | current_count[cpu][state] = |
73 | sysfs_get_idlestate_time(cpu, state); | 73 | cpuidle_state_time(cpu, state); |
74 | dprint("CPU %d - State: %d - Val: %llu\n", | 74 | dprint("CPU %d - State: %d - Val: %llu\n", |
75 | cpu, state, previous_count[cpu][state]); | 75 | cpu, state, previous_count[cpu][state]); |
76 | } | 76 | } |
@@ -132,13 +132,13 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
132 | char *tmp; | 132 | char *tmp; |
133 | 133 | ||
134 | /* Assume idle state count is the same for all CPUs */ | 134 | /* Assume idle state count is the same for all CPUs */ |
135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); | 135 | cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0); |
136 | 136 | ||
137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) | 137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) |
138 | return NULL; | 138 | return NULL; |
139 | 139 | ||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | 140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
141 | tmp = sysfs_get_idlestate_name(0, num); | 141 | tmp = cpuidle_state_name(0, num); |
142 | if (tmp == NULL) | 142 | if (tmp == NULL) |
143 | continue; | 143 | continue; |
144 | 144 | ||
@@ -146,7 +146,7 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); | 146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); |
147 | free(tmp); | 147 | free(tmp); |
148 | 148 | ||
149 | tmp = sysfs_get_idlestate_desc(0, num); | 149 | tmp = cpuidle_state_desc(0, num); |
150 | if (tmp == NULL) | 150 | if (tmp == NULL) |
151 | continue; | 151 | continue; |
152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); | 152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); |
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index a34bfd0c8928..785985677159 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild | |||
@@ -7,6 +7,7 @@ ldflags-y += --wrap=ioremap_nocache | |||
7 | ldflags-y += --wrap=iounmap | 7 | ldflags-y += --wrap=iounmap |
8 | ldflags-y += --wrap=memunmap | 8 | ldflags-y += --wrap=memunmap |
9 | ldflags-y += --wrap=__devm_request_region | 9 | ldflags-y += --wrap=__devm_request_region |
10 | ldflags-y += --wrap=__devm_release_region | ||
10 | ldflags-y += --wrap=__request_region | 11 | ldflags-y += --wrap=__request_region |
11 | ldflags-y += --wrap=__release_region | 12 | ldflags-y += --wrap=__release_region |
12 | ldflags-y += --wrap=devm_memremap_pages | 13 | ldflags-y += --wrap=devm_memremap_pages |
@@ -15,6 +16,7 @@ ldflags-y += --wrap=phys_to_pfn_t | |||
15 | DRIVERS := ../../../drivers | 16 | DRIVERS := ../../../drivers |
16 | NVDIMM_SRC := $(DRIVERS)/nvdimm | 17 | NVDIMM_SRC := $(DRIVERS)/nvdimm |
17 | ACPI_SRC := $(DRIVERS)/acpi | 18 | ACPI_SRC := $(DRIVERS)/acpi |
19 | DAX_SRC := $(DRIVERS)/dax | ||
18 | 20 | ||
19 | obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o | 21 | obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o |
20 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o | 22 | obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o |
@@ -22,6 +24,8 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o | |||
22 | obj-$(CONFIG_ND_BLK) += nd_blk.o | 24 | obj-$(CONFIG_ND_BLK) += nd_blk.o |
23 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o | 25 | obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o |
24 | obj-$(CONFIG_ACPI_NFIT) += nfit.o | 26 | obj-$(CONFIG_ACPI_NFIT) += nfit.o |
27 | obj-$(CONFIG_DEV_DAX) += dax.o | ||
28 | obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o | ||
25 | 29 | ||
26 | nfit-y := $(ACPI_SRC)/nfit.o | 30 | nfit-y := $(ACPI_SRC)/nfit.o |
27 | nfit-y += config_check.o | 31 | nfit-y += config_check.o |
@@ -38,6 +42,12 @@ nd_blk-y += config_check.o | |||
38 | nd_e820-y := $(NVDIMM_SRC)/e820.o | 42 | nd_e820-y := $(NVDIMM_SRC)/e820.o |
39 | nd_e820-y += config_check.o | 43 | nd_e820-y += config_check.o |
40 | 44 | ||
45 | dax-y := $(DAX_SRC)/dax.o | ||
46 | dax-y += config_check.o | ||
47 | |||
48 | dax_pmem-y := $(DAX_SRC)/pmem.o | ||
49 | dax_pmem-y += config_check.o | ||
50 | |||
41 | libnvdimm-y := $(NVDIMM_SRC)/core.o | 51 | libnvdimm-y := $(NVDIMM_SRC)/core.o |
42 | libnvdimm-y += $(NVDIMM_SRC)/bus.o | 52 | libnvdimm-y += $(NVDIMM_SRC)/bus.o |
43 | libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o | 53 | libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o |
@@ -49,6 +59,7 @@ libnvdimm-y += $(NVDIMM_SRC)/label.o | |||
49 | libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o | 59 | libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o |
50 | libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o | 60 | libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o |
51 | libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o | 61 | libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o |
62 | libnvdimm-$(CONFIG_NVDIMM_DAX) += $(NVDIMM_SRC)/dax_devs.o | ||
52 | libnvdimm-y += config_check.o | 63 | libnvdimm-y += config_check.o |
53 | 64 | ||
54 | obj-m += test/ | 65 | obj-m += test/ |
diff --git a/tools/testing/nvdimm/config_check.c b/tools/testing/nvdimm/config_check.c index f2c7615554eb..adf18bfeca00 100644 --- a/tools/testing/nvdimm/config_check.c +++ b/tools/testing/nvdimm/config_check.c | |||
@@ -12,4 +12,6 @@ void check(void) | |||
12 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT)); | 12 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT)); |
13 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK)); | 13 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK)); |
14 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT)); | 14 | BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT)); |
15 | BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX)); | ||
16 | BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX_PMEM)); | ||
15 | } | 17 | } |
diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index 0c1a7e65bb81..c842095f2801 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c | |||
@@ -239,13 +239,11 @@ struct resource *__wrap___devm_request_region(struct device *dev, | |||
239 | } | 239 | } |
240 | EXPORT_SYMBOL(__wrap___devm_request_region); | 240 | EXPORT_SYMBOL(__wrap___devm_request_region); |
241 | 241 | ||
242 | void __wrap___release_region(struct resource *parent, resource_size_t start, | 242 | static bool nfit_test_release_region(struct resource *parent, |
243 | resource_size_t n) | 243 | resource_size_t start, resource_size_t n) |
244 | { | 244 | { |
245 | struct nfit_test_resource *nfit_res; | ||
246 | |||
247 | if (parent == &iomem_resource) { | 245 | if (parent == &iomem_resource) { |
248 | nfit_res = get_nfit_res(start); | 246 | struct nfit_test_resource *nfit_res = get_nfit_res(start); |
249 | if (nfit_res) { | 247 | if (nfit_res) { |
250 | struct resource *res = nfit_res->res + 1; | 248 | struct resource *res = nfit_res->res + 1; |
251 | 249 | ||
@@ -254,11 +252,26 @@ void __wrap___release_region(struct resource *parent, resource_size_t start, | |||
254 | __func__, start, n, res); | 252 | __func__, start, n, res); |
255 | else | 253 | else |
256 | memset(res, 0, sizeof(*res)); | 254 | memset(res, 0, sizeof(*res)); |
257 | return; | 255 | return true; |
258 | } | 256 | } |
259 | } | 257 | } |
260 | __release_region(parent, start, n); | 258 | return false; |
259 | } | ||
260 | |||
261 | void __wrap___release_region(struct resource *parent, resource_size_t start, | ||
262 | resource_size_t n) | ||
263 | { | ||
264 | if (!nfit_test_release_region(parent, start, n)) | ||
265 | __release_region(parent, start, n); | ||
261 | } | 266 | } |
262 | EXPORT_SYMBOL(__wrap___release_region); | 267 | EXPORT_SYMBOL(__wrap___release_region); |
263 | 268 | ||
269 | void __wrap___devm_release_region(struct device *dev, struct resource *parent, | ||
270 | resource_size_t start, resource_size_t n) | ||
271 | { | ||
272 | if (!nfit_test_release_region(parent, start, n)) | ||
273 | __devm_release_region(dev, parent, start, n); | ||
274 | } | ||
275 | EXPORT_SYMBOL(__wrap___devm_release_region); | ||
276 | |||
264 | MODULE_LICENSE("GPL v2"); | 277 | MODULE_LICENSE("GPL v2"); |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 3187322eeed7..c919866853a0 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -330,12 +330,49 @@ static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err, | |||
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len) | ||
334 | { | ||
335 | static const struct nd_smart_payload smart_data = { | ||
336 | .flags = ND_SMART_HEALTH_VALID | ND_SMART_TEMP_VALID | ||
337 | | ND_SMART_SPARES_VALID | ND_SMART_ALARM_VALID | ||
338 | | ND_SMART_USED_VALID | ND_SMART_SHUTDOWN_VALID, | ||
339 | .health = ND_SMART_NON_CRITICAL_HEALTH, | ||
340 | .temperature = 23 * 16, | ||
341 | .spares = 75, | ||
342 | .alarm_flags = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP, | ||
343 | .life_used = 5, | ||
344 | .shutdown_state = 0, | ||
345 | .vendor_size = 0, | ||
346 | }; | ||
347 | |||
348 | if (buf_len < sizeof(*smart)) | ||
349 | return -EINVAL; | ||
350 | memcpy(smart->data, &smart_data, sizeof(smart_data)); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int nfit_test_cmd_smart_threshold(struct nd_cmd_smart_threshold *smart_t, | ||
355 | unsigned int buf_len) | ||
356 | { | ||
357 | static const struct nd_smart_threshold_payload smart_t_data = { | ||
358 | .alarm_control = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP, | ||
359 | .temperature = 40 * 16, | ||
360 | .spares = 5, | ||
361 | }; | ||
362 | |||
363 | if (buf_len < sizeof(*smart_t)) | ||
364 | return -EINVAL; | ||
365 | memcpy(smart_t->data, &smart_t_data, sizeof(smart_t_data)); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
333 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | 369 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, |
334 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, | 370 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
335 | unsigned int buf_len, int *cmd_rc) | 371 | unsigned int buf_len, int *cmd_rc) |
336 | { | 372 | { |
337 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 373 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
338 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); | 374 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); |
375 | unsigned int func = cmd; | ||
339 | int i, rc = 0, __cmd_rc; | 376 | int i, rc = 0, __cmd_rc; |
340 | 377 | ||
341 | if (!cmd_rc) | 378 | if (!cmd_rc) |
@@ -344,8 +381,23 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
344 | 381 | ||
345 | if (nvdimm) { | 382 | if (nvdimm) { |
346 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 383 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); |
384 | unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); | ||
347 | 385 | ||
348 | if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) | 386 | if (!nfit_mem) |
387 | return -ENOTTY; | ||
388 | |||
389 | if (cmd == ND_CMD_CALL) { | ||
390 | struct nd_cmd_pkg *call_pkg = buf; | ||
391 | |||
392 | buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; | ||
393 | buf = (void *) call_pkg->nd_payload; | ||
394 | func = call_pkg->nd_command; | ||
395 | if (call_pkg->nd_family != nfit_mem->family) | ||
396 | return -ENOTTY; | ||
397 | } | ||
398 | |||
399 | if (!test_bit(cmd, &cmd_mask) | ||
400 | || !test_bit(func, &nfit_mem->dsm_mask)) | ||
349 | return -ENOTTY; | 401 | return -ENOTTY; |
350 | 402 | ||
351 | /* lookup label space for the given dimm */ | 403 | /* lookup label space for the given dimm */ |
@@ -356,7 +408,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
356 | if (i >= ARRAY_SIZE(handle)) | 408 | if (i >= ARRAY_SIZE(handle)) |
357 | return -ENXIO; | 409 | return -ENXIO; |
358 | 410 | ||
359 | switch (cmd) { | 411 | switch (func) { |
360 | case ND_CMD_GET_CONFIG_SIZE: | 412 | case ND_CMD_GET_CONFIG_SIZE: |
361 | rc = nfit_test_cmd_get_config_size(buf, buf_len); | 413 | rc = nfit_test_cmd_get_config_size(buf, buf_len); |
362 | break; | 414 | break; |
@@ -368,16 +420,22 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
368 | rc = nfit_test_cmd_set_config_data(buf, buf_len, | 420 | rc = nfit_test_cmd_set_config_data(buf, buf_len, |
369 | t->label[i]); | 421 | t->label[i]); |
370 | break; | 422 | break; |
423 | case ND_CMD_SMART: | ||
424 | rc = nfit_test_cmd_smart(buf, buf_len); | ||
425 | break; | ||
426 | case ND_CMD_SMART_THRESHOLD: | ||
427 | rc = nfit_test_cmd_smart_threshold(buf, buf_len); | ||
428 | break; | ||
371 | default: | 429 | default: |
372 | return -ENOTTY; | 430 | return -ENOTTY; |
373 | } | 431 | } |
374 | } else { | 432 | } else { |
375 | struct ars_state *ars_state = &t->ars_state; | 433 | struct ars_state *ars_state = &t->ars_state; |
376 | 434 | ||
377 | if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) | 435 | if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) |
378 | return -ENOTTY; | 436 | return -ENOTTY; |
379 | 437 | ||
380 | switch (cmd) { | 438 | switch (func) { |
381 | case ND_CMD_ARS_CAP: | 439 | case ND_CMD_ARS_CAP: |
382 | rc = nfit_test_cmd_ars_cap(buf, buf_len); | 440 | rc = nfit_test_cmd_ars_cap(buf, buf_len); |
383 | break; | 441 | break; |
@@ -1251,13 +1309,15 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1251 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); | 1309 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); |
1252 | 1310 | ||
1253 | acpi_desc = &t->acpi_desc; | 1311 | acpi_desc = &t->acpi_desc; |
1254 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); | 1312 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); |
1255 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1313 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
1256 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 1314 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); |
1257 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | 1315 | set_bit(ND_CMD_SMART, &acpi_desc->dimm_cmd_force_en); |
1258 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | 1316 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
1259 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | 1317 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
1260 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); | 1318 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
1319 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); | ||
1320 | set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | ||
1261 | } | 1321 | } |
1262 | 1322 | ||
1263 | static void nfit_test1_setup(struct nfit_test *t) | 1323 | static void nfit_test1_setup(struct nfit_test *t) |
@@ -1315,10 +1375,10 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
1315 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); | 1375 | post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); |
1316 | 1376 | ||
1317 | acpi_desc = &t->acpi_desc; | 1377 | acpi_desc = &t->acpi_desc; |
1318 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | 1378 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
1319 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | 1379 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
1320 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | 1380 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
1321 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); | 1381 | set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); |
1322 | } | 1382 | } |
1323 | 1383 | ||
1324 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, | 1384 | static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, |
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile index 604212db9d4b..3b530467148e 100644 --- a/tools/testing/radix-tree/Makefile +++ b/tools/testing/radix-tree/Makefile | |||
@@ -3,7 +3,7 @@ CFLAGS += -I. -g -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 | 6 | regression1.o regression2.o regression3.o multiorder.o |
7 | 7 | ||
8 | targets: $(TARGETS) | 8 | targets: $(TARGETS) |
9 | 9 | ||
@@ -13,7 +13,7 @@ main: $(OFILES) | |||
13 | clean: | 13 | clean: |
14 | $(RM) -f $(TARGETS) *.o radix-tree.c | 14 | $(RM) -f $(TARGETS) *.o radix-tree.c |
15 | 15 | ||
16 | $(OFILES): *.h */*.h | 16 | $(OFILES): *.h */*.h ../../../include/linux/radix-tree.h ../../include/linux/*.h |
17 | 17 | ||
18 | radix-tree.c: ../../../lib/radix-tree.c | 18 | radix-tree.c: ../../../lib/radix-tree.c |
19 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ | 19 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ |
diff --git a/tools/testing/radix-tree/generated/autoconf.h b/tools/testing/radix-tree/generated/autoconf.h new file mode 100644 index 000000000000..ad18cf5a2a3a --- /dev/null +++ b/tools/testing/radix-tree/generated/autoconf.h | |||
@@ -0,0 +1,3 @@ | |||
1 | #define CONFIG_RADIX_TREE_MULTIORDER 1 | ||
2 | #define CONFIG_SHMEM 1 | ||
3 | #define CONFIG_SWAP 1 | ||
diff --git a/tools/testing/radix-tree/linux/init.h b/tools/testing/radix-tree/linux/init.h new file mode 100644 index 000000000000..360cabb3c4e7 --- /dev/null +++ b/tools/testing/radix-tree/linux/init.h | |||
@@ -0,0 +1 @@ | |||
/* An empty file stub that allows radix-tree.c to compile. */ | |||
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h index ae013b0160ac..be98a47b4e1b 100644 --- a/tools/testing/radix-tree/linux/kernel.h +++ b/tools/testing/radix-tree/linux/kernel.h | |||
@@ -7,19 +7,28 @@ | |||
7 | #include <stddef.h> | 7 | #include <stddef.h> |
8 | #include <limits.h> | 8 | #include <limits.h> |
9 | 9 | ||
10 | #include "../../include/linux/compiler.h" | ||
11 | #include "../../../include/linux/kconfig.h" | ||
12 | |||
13 | #define RADIX_TREE_MAP_SHIFT 3 | ||
14 | |||
10 | #ifndef NULL | 15 | #ifndef NULL |
11 | #define NULL 0 | 16 | #define NULL 0 |
12 | #endif | 17 | #endif |
13 | 18 | ||
14 | #define BUG_ON(expr) assert(!(expr)) | 19 | #define BUG_ON(expr) assert(!(expr)) |
20 | #define WARN_ON(expr) assert(!(expr)) | ||
15 | #define __init | 21 | #define __init |
16 | #define __must_check | 22 | #define __must_check |
17 | #define panic(expr) | 23 | #define panic(expr) |
18 | #define printk printf | 24 | #define printk printf |
19 | #define __force | 25 | #define __force |
20 | #define likely(c) (c) | ||
21 | #define unlikely(c) (c) | ||
22 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) | 26 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) |
27 | #define pr_debug printk | ||
28 | |||
29 | #define smp_rmb() barrier() | ||
30 | #define smp_wmb() barrier() | ||
31 | #define cpu_relax() barrier() | ||
23 | 32 | ||
24 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | 33 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) |
25 | 34 | ||
@@ -28,6 +37,8 @@ | |||
28 | (type *)( (char *)__mptr - offsetof(type, member) );}) | 37 | (type *)( (char *)__mptr - offsetof(type, member) );}) |
29 | #define min(a, b) ((a) < (b) ? (a) : (b)) | 38 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
30 | 39 | ||
40 | #define cond_resched() sched_yield() | ||
41 | |||
31 | static inline int in_interrupt(void) | 42 | static inline int in_interrupt(void) |
32 | { | 43 | { |
33 | return 0; | 44 | return 0; |
diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h index 57282506c21d..6d5a34770fd4 100644 --- a/tools/testing/radix-tree/linux/slab.h +++ b/tools/testing/radix-tree/linux/slab.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | #define GFP_KERNEL 1 | ||
7 | #define SLAB_HWCACHE_ALIGN 1 | 6 | #define SLAB_HWCACHE_ALIGN 1 |
8 | #define SLAB_PANIC 2 | 7 | #define SLAB_PANIC 2 |
9 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ | 8 | #define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ |
diff --git a/tools/testing/radix-tree/linux/types.h b/tools/testing/radix-tree/linux/types.h index 72a9d85f6c76..faa0b6ff9ca8 100644 --- a/tools/testing/radix-tree/linux/types.h +++ b/tools/testing/radix-tree/linux/types.h | |||
@@ -1,15 +1,13 @@ | |||
1 | #ifndef _TYPES_H | 1 | #ifndef _TYPES_H |
2 | #define _TYPES_H | 2 | #define _TYPES_H |
3 | 3 | ||
4 | #include "../../include/linux/types.h" | ||
5 | |||
4 | #define __rcu | 6 | #define __rcu |
5 | #define __read_mostly | 7 | #define __read_mostly |
6 | 8 | ||
7 | #define BITS_PER_LONG (sizeof(long) * 8) | 9 | #define BITS_PER_LONG (sizeof(long) * 8) |
8 | 10 | ||
9 | struct list_head { | ||
10 | struct list_head *next, *prev; | ||
11 | }; | ||
12 | |||
13 | static inline void INIT_LIST_HEAD(struct list_head *list) | 11 | static inline void INIT_LIST_HEAD(struct list_head *list) |
14 | { | 12 | { |
15 | list->next = list; | 13 | list->next = list; |
@@ -22,7 +20,6 @@ typedef struct { | |||
22 | 20 | ||
23 | #define uninitialized_var(x) x = x | 21 | #define uninitialized_var(x) x = x |
24 | 22 | ||
25 | typedef unsigned gfp_t; | ||
26 | #include <linux/gfp.h> | 23 | #include <linux/gfp.h> |
27 | 24 | ||
28 | #endif | 25 | #endif |
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c index 0e83cad27a9f..b7619ff3b552 100644 --- a/tools/testing/radix-tree/main.c +++ b/tools/testing/radix-tree/main.c | |||
@@ -61,11 +61,11 @@ void __big_gang_check(void) | |||
61 | } while (!wrapped); | 61 | } while (!wrapped); |
62 | } | 62 | } |
63 | 63 | ||
64 | void big_gang_check(void) | 64 | void big_gang_check(bool long_run) |
65 | { | 65 | { |
66 | int i; | 66 | int i; |
67 | 67 | ||
68 | for (i = 0; i < 1000; i++) { | 68 | for (i = 0; i < (long_run ? 1000 : 3); i++) { |
69 | __big_gang_check(); | 69 | __big_gang_check(); |
70 | srand(time(0)); | 70 | srand(time(0)); |
71 | printf("%d ", i); | 71 | printf("%d ", i); |
@@ -232,10 +232,72 @@ void copy_tag_check(void) | |||
232 | item_kill_tree(&tree); | 232 | item_kill_tree(&tree); |
233 | } | 233 | } |
234 | 234 | ||
235 | static void single_thread_tests(void) | 235 | static void __locate_check(struct radix_tree_root *tree, unsigned long index, |
236 | unsigned order) | ||
237 | { | ||
238 | struct item *item; | ||
239 | unsigned long index2; | ||
240 | |||
241 | item_insert_order(tree, index, order); | ||
242 | item = item_lookup(tree, index); | ||
243 | index2 = radix_tree_locate_item(tree, item); | ||
244 | if (index != index2) { | ||
245 | printf("index %ld order %d inserted; found %ld\n", | ||
246 | index, order, index2); | ||
247 | abort(); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | static void __order_0_locate_check(void) | ||
252 | { | ||
253 | RADIX_TREE(tree, GFP_KERNEL); | ||
254 | int i; | ||
255 | |||
256 | for (i = 0; i < 50; i++) | ||
257 | __locate_check(&tree, rand() % INT_MAX, 0); | ||
258 | |||
259 | item_kill_tree(&tree); | ||
260 | } | ||
261 | |||
262 | static void locate_check(void) | ||
263 | { | ||
264 | RADIX_TREE(tree, GFP_KERNEL); | ||
265 | unsigned order; | ||
266 | unsigned long offset, index; | ||
267 | |||
268 | __order_0_locate_check(); | ||
269 | |||
270 | for (order = 0; order < 20; order++) { | ||
271 | for (offset = 0; offset < (1 << (order + 3)); | ||
272 | offset += (1UL << order)) { | ||
273 | for (index = 0; index < (1UL << (order + 5)); | ||
274 | index += (1UL << order)) { | ||
275 | __locate_check(&tree, index + offset, order); | ||
276 | } | ||
277 | if (radix_tree_locate_item(&tree, &tree) != -1) | ||
278 | abort(); | ||
279 | |||
280 | item_kill_tree(&tree); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (radix_tree_locate_item(&tree, &tree) != -1) | ||
285 | abort(); | ||
286 | __locate_check(&tree, -1, 0); | ||
287 | if (radix_tree_locate_item(&tree, &tree) != -1) | ||
288 | abort(); | ||
289 | item_kill_tree(&tree); | ||
290 | } | ||
291 | |||
292 | static void single_thread_tests(bool long_run) | ||
236 | { | 293 | { |
237 | int i; | 294 | int i; |
238 | 295 | ||
296 | printf("starting single_thread_tests: %d allocated\n", nr_allocated); | ||
297 | multiorder_checks(); | ||
298 | printf("after multiorder_check: %d allocated\n", nr_allocated); | ||
299 | locate_check(); | ||
300 | printf("after locate_check: %d allocated\n", nr_allocated); | ||
239 | tag_check(); | 301 | tag_check(); |
240 | printf("after tag_check: %d allocated\n", nr_allocated); | 302 | printf("after tag_check: %d allocated\n", nr_allocated); |
241 | gang_check(); | 303 | gang_check(); |
@@ -244,9 +306,9 @@ static void single_thread_tests(void) | |||
244 | printf("after add_and_check: %d allocated\n", nr_allocated); | 306 | printf("after add_and_check: %d allocated\n", nr_allocated); |
245 | dynamic_height_check(); | 307 | dynamic_height_check(); |
246 | printf("after dynamic_height_check: %d allocated\n", nr_allocated); | 308 | printf("after dynamic_height_check: %d allocated\n", nr_allocated); |
247 | big_gang_check(); | 309 | big_gang_check(long_run); |
248 | printf("after big_gang_check: %d allocated\n", nr_allocated); | 310 | printf("after big_gang_check: %d allocated\n", nr_allocated); |
249 | for (i = 0; i < 2000; i++) { | 311 | for (i = 0; i < (long_run ? 2000 : 3); i++) { |
250 | copy_tag_check(); | 312 | copy_tag_check(); |
251 | printf("%d ", i); | 313 | printf("%d ", i); |
252 | fflush(stdout); | 314 | fflush(stdout); |
@@ -254,15 +316,23 @@ static void single_thread_tests(void) | |||
254 | printf("after copy_tag_check: %d allocated\n", nr_allocated); | 316 | printf("after copy_tag_check: %d allocated\n", nr_allocated); |
255 | } | 317 | } |
256 | 318 | ||
257 | int main(void) | 319 | int main(int argc, char **argv) |
258 | { | 320 | { |
321 | bool long_run = false; | ||
322 | int opt; | ||
323 | |||
324 | while ((opt = getopt(argc, argv, "l")) != -1) { | ||
325 | if (opt == 'l') | ||
326 | long_run = true; | ||
327 | } | ||
328 | |||
259 | rcu_register_thread(); | 329 | rcu_register_thread(); |
260 | radix_tree_init(); | 330 | radix_tree_init(); |
261 | 331 | ||
262 | regression1_test(); | 332 | regression1_test(); |
263 | regression2_test(); | 333 | regression2_test(); |
264 | regression3_test(); | 334 | regression3_test(); |
265 | single_thread_tests(); | 335 | single_thread_tests(long_run); |
266 | 336 | ||
267 | sleep(1); | 337 | sleep(1); |
268 | printf("after sleep(1): %d allocated\n", nr_allocated); | 338 | printf("after sleep(1): %d allocated\n", nr_allocated); |
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c new file mode 100644 index 000000000000..39d9b9568fe2 --- /dev/null +++ b/tools/testing/radix-tree/multiorder.c | |||
@@ -0,0 +1,337 @@ | |||
1 | /* | ||
2 | * multiorder.c: Multi-order radix tree entry testing | ||
3 | * Copyright (c) 2016 Intel Corporation | ||
4 | * Author: Ross Zwisler <ross.zwisler@linux.intel.com> | ||
5 | * Author: Matthew Wilcox <matthew.r.wilcox@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | */ | ||
16 | #include <linux/radix-tree.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/errno.h> | ||
19 | |||
20 | #include "test.h" | ||
21 | |||
22 | #define for_each_index(i, base, order) \ | ||
23 | for (i = base; i < base + (1 << order); i++) | ||
24 | |||
25 | static void __multiorder_tag_test(int index, int order) | ||
26 | { | ||
27 | RADIX_TREE(tree, GFP_KERNEL); | ||
28 | int base, err, i; | ||
29 | unsigned long first = 0; | ||
30 | |||
31 | /* our canonical entry */ | ||
32 | base = index & ~((1 << order) - 1); | ||
33 | |||
34 | printf("Multiorder tag test with index %d, canonical entry %d\n", | ||
35 | index, base); | ||
36 | |||
37 | err = item_insert_order(&tree, index, order); | ||
38 | assert(!err); | ||
39 | |||
40 | /* | ||
41 | * Verify we get collisions for covered indices. We try and fail to | ||
42 | * insert an exceptional entry so we don't leak memory via | ||
43 | * item_insert_order(). | ||
44 | */ | ||
45 | for_each_index(i, base, order) { | ||
46 | err = __radix_tree_insert(&tree, i, order, | ||
47 | (void *)(0xA0 | RADIX_TREE_EXCEPTIONAL_ENTRY)); | ||
48 | assert(err == -EEXIST); | ||
49 | } | ||
50 | |||
51 | for_each_index(i, base, order) { | ||
52 | assert(!radix_tree_tag_get(&tree, i, 0)); | ||
53 | assert(!radix_tree_tag_get(&tree, i, 1)); | ||
54 | } | ||
55 | |||
56 | assert(radix_tree_tag_set(&tree, index, 0)); | ||
57 | |||
58 | for_each_index(i, base, order) { | ||
59 | assert(radix_tree_tag_get(&tree, i, 0)); | ||
60 | assert(!radix_tree_tag_get(&tree, i, 1)); | ||
61 | } | ||
62 | |||
63 | assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1); | ||
64 | assert(radix_tree_tag_clear(&tree, index, 0)); | ||
65 | |||
66 | for_each_index(i, base, order) { | ||
67 | assert(!radix_tree_tag_get(&tree, i, 0)); | ||
68 | assert(radix_tree_tag_get(&tree, i, 1)); | ||
69 | } | ||
70 | |||
71 | assert(radix_tree_tag_clear(&tree, index, 1)); | ||
72 | |||
73 | assert(!radix_tree_tagged(&tree, 0)); | ||
74 | assert(!radix_tree_tagged(&tree, 1)); | ||
75 | |||
76 | item_kill_tree(&tree); | ||
77 | } | ||
78 | |||
79 | static void multiorder_tag_tests(void) | ||
80 | { | ||
81 | /* test multi-order entry for indices 0-7 with no sibling pointers */ | ||
82 | __multiorder_tag_test(0, 3); | ||
83 | __multiorder_tag_test(5, 3); | ||
84 | |||
85 | /* test multi-order entry for indices 8-15 with no sibling pointers */ | ||
86 | __multiorder_tag_test(8, 3); | ||
87 | __multiorder_tag_test(15, 3); | ||
88 | |||
89 | /* | ||
90 | * Our order 5 entry covers indices 0-31 in a tree with height=2. | ||
91 | * This is broken up as follows: | ||
92 | * 0-7: canonical entry | ||
93 | * 8-15: sibling 1 | ||
94 | * 16-23: sibling 2 | ||
95 | * 24-31: sibling 3 | ||
96 | */ | ||
97 | __multiorder_tag_test(0, 5); | ||
98 | __multiorder_tag_test(29, 5); | ||
99 | |||
100 | /* same test, but with indices 32-63 */ | ||
101 | __multiorder_tag_test(32, 5); | ||
102 | __multiorder_tag_test(44, 5); | ||
103 | |||
104 | /* | ||
105 | * Our order 8 entry covers indices 0-255 in a tree with height=3. | ||
106 | * This is broken up as follows: | ||
107 | * 0-63: canonical entry | ||
108 | * 64-127: sibling 1 | ||
109 | * 128-191: sibling 2 | ||
110 | * 192-255: sibling 3 | ||
111 | */ | ||
112 | __multiorder_tag_test(0, 8); | ||
113 | __multiorder_tag_test(190, 8); | ||
114 | |||
115 | /* same test, but with indices 256-511 */ | ||
116 | __multiorder_tag_test(256, 8); | ||
117 | __multiorder_tag_test(300, 8); | ||
118 | |||
119 | __multiorder_tag_test(0x12345678UL, 8); | ||
120 | } | ||
121 | |||
122 | static void multiorder_check(unsigned long index, int order) | ||
123 | { | ||
124 | unsigned long i; | ||
125 | unsigned long min = index & ~((1UL << order) - 1); | ||
126 | unsigned long max = min + (1UL << order); | ||
127 | RADIX_TREE(tree, GFP_KERNEL); | ||
128 | |||
129 | printf("Multiorder index %ld, order %d\n", index, order); | ||
130 | |||
131 | assert(item_insert_order(&tree, index, order) == 0); | ||
132 | |||
133 | for (i = min; i < max; i++) { | ||
134 | struct item *item = item_lookup(&tree, i); | ||
135 | assert(item != 0); | ||
136 | assert(item->index == index); | ||
137 | } | ||
138 | for (i = 0; i < min; i++) | ||
139 | item_check_absent(&tree, i); | ||
140 | for (i = max; i < 2*max; i++) | ||
141 | item_check_absent(&tree, i); | ||
142 | for (i = min; i < max; i++) { | ||
143 | static void *entry = (void *) | ||
144 | (0xA0 | RADIX_TREE_EXCEPTIONAL_ENTRY); | ||
145 | assert(radix_tree_insert(&tree, i, entry) == -EEXIST); | ||
146 | } | ||
147 | |||
148 | assert(item_delete(&tree, index) != 0); | ||
149 | |||
150 | for (i = 0; i < 2*max; i++) | ||
151 | item_check_absent(&tree, i); | ||
152 | } | ||
153 | |||
154 | static void multiorder_shrink(unsigned long index, int order) | ||
155 | { | ||
156 | unsigned long i; | ||
157 | unsigned long max = 1 << order; | ||
158 | RADIX_TREE(tree, GFP_KERNEL); | ||
159 | struct radix_tree_node *node; | ||
160 | |||
161 | printf("Multiorder shrink index %ld, order %d\n", index, order); | ||
162 | |||
163 | assert(item_insert_order(&tree, 0, order) == 0); | ||
164 | |||
165 | node = tree.rnode; | ||
166 | |||
167 | assert(item_insert(&tree, index) == 0); | ||
168 | assert(node != tree.rnode); | ||
169 | |||
170 | assert(item_delete(&tree, index) != 0); | ||
171 | assert(node == tree.rnode); | ||
172 | |||
173 | for (i = 0; i < max; i++) { | ||
174 | struct item *item = item_lookup(&tree, i); | ||
175 | assert(item != 0); | ||
176 | assert(item->index == 0); | ||
177 | } | ||
178 | for (i = max; i < 2*max; i++) | ||
179 | item_check_absent(&tree, i); | ||
180 | |||
181 | if (!item_delete(&tree, 0)) { | ||
182 | printf("failed to delete index %ld (order %d)\n", index, order); abort(); | ||
183 | } | ||
184 | |||
185 | for (i = 0; i < 2*max; i++) | ||
186 | item_check_absent(&tree, i); | ||
187 | } | ||
188 | |||
189 | static void multiorder_insert_bug(void) | ||
190 | { | ||
191 | RADIX_TREE(tree, GFP_KERNEL); | ||
192 | |||
193 | item_insert(&tree, 0); | ||
194 | radix_tree_tag_set(&tree, 0, 0); | ||
195 | item_insert_order(&tree, 3 << 6, 6); | ||
196 | |||
197 | item_kill_tree(&tree); | ||
198 | } | ||
199 | |||
200 | void multiorder_iteration(void) | ||
201 | { | ||
202 | RADIX_TREE(tree, GFP_KERNEL); | ||
203 | struct radix_tree_iter iter; | ||
204 | void **slot; | ||
205 | int i, j, err; | ||
206 | |||
207 | printf("Multiorder iteration test\n"); | ||
208 | |||
209 | #define NUM_ENTRIES 11 | ||
210 | int index[NUM_ENTRIES] = {0, 2, 4, 8, 16, 32, 34, 36, 64, 72, 128}; | ||
211 | int order[NUM_ENTRIES] = {1, 1, 2, 3, 4, 1, 0, 1, 3, 0, 7}; | ||
212 | |||
213 | for (i = 0; i < NUM_ENTRIES; i++) { | ||
214 | err = item_insert_order(&tree, index[i], order[i]); | ||
215 | assert(!err); | ||
216 | } | ||
217 | |||
218 | for (j = 0; j < 256; j++) { | ||
219 | for (i = 0; i < NUM_ENTRIES; i++) | ||
220 | if (j <= (index[i] | ((1 << order[i]) - 1))) | ||
221 | break; | ||
222 | |||
223 | radix_tree_for_each_slot(slot, &tree, &iter, j) { | ||
224 | int height = order[i] / RADIX_TREE_MAP_SHIFT; | ||
225 | int shift = height * RADIX_TREE_MAP_SHIFT; | ||
226 | int mask = (1 << order[i]) - 1; | ||
227 | |||
228 | assert(iter.index >= (index[i] &~ mask)); | ||
229 | assert(iter.index <= (index[i] | mask)); | ||
230 | assert(iter.shift == shift); | ||
231 | i++; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | item_kill_tree(&tree); | ||
236 | } | ||
237 | |||
238 | void multiorder_tagged_iteration(void) | ||
239 | { | ||
240 | RADIX_TREE(tree, GFP_KERNEL); | ||
241 | struct radix_tree_iter iter; | ||
242 | void **slot; | ||
243 | unsigned long first = 0; | ||
244 | int i, j; | ||
245 | |||
246 | printf("Multiorder tagged iteration test\n"); | ||
247 | |||
248 | #define MT_NUM_ENTRIES 9 | ||
249 | int index[MT_NUM_ENTRIES] = {0, 2, 4, 16, 32, 40, 64, 72, 128}; | ||
250 | int order[MT_NUM_ENTRIES] = {1, 0, 2, 4, 3, 1, 3, 0, 7}; | ||
251 | |||
252 | #define TAG_ENTRIES 7 | ||
253 | int tag_index[TAG_ENTRIES] = {0, 4, 16, 40, 64, 72, 128}; | ||
254 | |||
255 | for (i = 0; i < MT_NUM_ENTRIES; i++) | ||
256 | assert(!item_insert_order(&tree, index[i], order[i])); | ||
257 | |||
258 | assert(!radix_tree_tagged(&tree, 1)); | ||
259 | |||
260 | for (i = 0; i < TAG_ENTRIES; i++) | ||
261 | assert(radix_tree_tag_set(&tree, tag_index[i], 1)); | ||
262 | |||
263 | for (j = 0; j < 256; j++) { | ||
264 | int mask, k; | ||
265 | |||
266 | for (i = 0; i < TAG_ENTRIES; i++) { | ||
267 | for (k = i; index[k] < tag_index[i]; k++) | ||
268 | ; | ||
269 | if (j <= (index[k] | ((1 << order[k]) - 1))) | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { | ||
274 | for (k = i; index[k] < tag_index[i]; k++) | ||
275 | ; | ||
276 | mask = (1 << order[k]) - 1; | ||
277 | |||
278 | assert(iter.index >= (tag_index[i] &~ mask)); | ||
279 | assert(iter.index <= (tag_index[i] | mask)); | ||
280 | i++; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | ||
285 | MT_NUM_ENTRIES, 1, 2); | ||
286 | |||
287 | for (j = 0; j < 256; j++) { | ||
288 | int mask, k; | ||
289 | |||
290 | for (i = 0; i < TAG_ENTRIES; i++) { | ||
291 | for (k = i; index[k] < tag_index[i]; k++) | ||
292 | ; | ||
293 | if (j <= (index[k] | ((1 << order[k]) - 1))) | ||
294 | break; | ||
295 | } | ||
296 | |||
297 | radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { | ||
298 | for (k = i; index[k] < tag_index[i]; k++) | ||
299 | ; | ||
300 | mask = (1 << order[k]) - 1; | ||
301 | |||
302 | assert(iter.index >= (tag_index[i] &~ mask)); | ||
303 | assert(iter.index <= (tag_index[i] | mask)); | ||
304 | i++; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | first = 1; | ||
309 | radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, | ||
310 | MT_NUM_ENTRIES, 1, 0); | ||
311 | i = 0; | ||
312 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { | ||
313 | assert(iter.index == tag_index[i]); | ||
314 | i++; | ||
315 | } | ||
316 | |||
317 | item_kill_tree(&tree); | ||
318 | } | ||
319 | |||
320 | void multiorder_checks(void) | ||
321 | { | ||
322 | int i; | ||
323 | |||
324 | for (i = 0; i < 20; i++) { | ||
325 | multiorder_check(200, i); | ||
326 | multiorder_check(0, i); | ||
327 | multiorder_check((1UL << i) + 1, i); | ||
328 | } | ||
329 | |||
330 | for (i = 0; i < 15; i++) | ||
331 | multiorder_shrink((1UL << (i + RADIX_TREE_MAP_SHIFT)), i); | ||
332 | |||
333 | multiorder_insert_bug(); | ||
334 | multiorder_tag_tests(); | ||
335 | multiorder_iteration(); | ||
336 | multiorder_tagged_iteration(); | ||
337 | } | ||
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c index 5d2fa28cdca3..63bf347aaf33 100644 --- a/tools/testing/radix-tree/regression2.c +++ b/tools/testing/radix-tree/regression2.c | |||
@@ -51,13 +51,6 @@ | |||
51 | 51 | ||
52 | #include "regression.h" | 52 | #include "regression.h" |
53 | 53 | ||
54 | #ifdef __KERNEL__ | ||
55 | #define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6) | ||
56 | #else | ||
57 | #define RADIX_TREE_MAP_SHIFT 3 /* For more stressful testing */ | ||
58 | #endif | ||
59 | |||
60 | #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) | ||
61 | #define PAGECACHE_TAG_DIRTY 0 | 54 | #define PAGECACHE_TAG_DIRTY 0 |
62 | #define PAGECACHE_TAG_WRITEBACK 1 | 55 | #define PAGECACHE_TAG_WRITEBACK 1 |
63 | #define PAGECACHE_TAG_TOWRITE 2 | 56 | #define PAGECACHE_TAG_TOWRITE 2 |
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c index 83136be552a0..b7447ceb75e9 100644 --- a/tools/testing/radix-tree/tag_check.c +++ b/tools/testing/radix-tree/tag_check.c | |||
@@ -12,6 +12,7 @@ | |||
12 | static void | 12 | static void |
13 | __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag) | 13 | __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag) |
14 | { | 14 | { |
15 | unsigned long first = 0; | ||
15 | int ret; | 16 | int ret; |
16 | 17 | ||
17 | item_check_absent(tree, index); | 18 | item_check_absent(tree, index); |
@@ -22,6 +23,10 @@ __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag) | |||
22 | item_tag_set(tree, index, tag); | 23 | item_tag_set(tree, index, tag); |
23 | ret = item_tag_get(tree, index, tag); | 24 | ret = item_tag_get(tree, index, tag); |
24 | assert(ret != 0); | 25 | assert(ret != 0); |
26 | ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag); | ||
27 | assert(ret == 1); | ||
28 | ret = item_tag_get(tree, index, !tag); | ||
29 | assert(ret != 0); | ||
25 | ret = item_delete(tree, index); | 30 | ret = item_delete(tree, index); |
26 | assert(ret != 0); | 31 | assert(ret != 0); |
27 | item_insert(tree, index); | 32 | item_insert(tree, index); |
@@ -304,6 +309,7 @@ static void single_check(void) | |||
304 | struct item *items[BATCH]; | 309 | struct item *items[BATCH]; |
305 | RADIX_TREE(tree, GFP_KERNEL); | 310 | RADIX_TREE(tree, GFP_KERNEL); |
306 | int ret; | 311 | int ret; |
312 | unsigned long first = 0; | ||
307 | 313 | ||
308 | item_insert(&tree, 0); | 314 | item_insert(&tree, 0); |
309 | item_tag_set(&tree, 0, 0); | 315 | item_tag_set(&tree, 0, 0); |
@@ -313,6 +319,10 @@ static void single_check(void) | |||
313 | assert(ret == 0); | 319 | assert(ret == 0); |
314 | verify_tag_consistency(&tree, 0); | 320 | verify_tag_consistency(&tree, 0); |
315 | verify_tag_consistency(&tree, 1); | 321 | verify_tag_consistency(&tree, 1); |
322 | ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1); | ||
323 | assert(ret == 1); | ||
324 | ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); | ||
325 | assert(ret == 1); | ||
316 | item_kill_tree(&tree); | 326 | item_kill_tree(&tree); |
317 | } | 327 | } |
318 | 328 | ||
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c index 2bebf34cdc27..a6e8099eaf4f 100644 --- a/tools/testing/radix-tree/test.c +++ b/tools/testing/radix-tree/test.c | |||
@@ -24,14 +24,21 @@ 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) | ||
28 | { | 29 | { |
29 | return radix_tree_insert(root, item->index, item); | 30 | return __radix_tree_insert(root, item->index, order, item); |
30 | } | 31 | } |
31 | 32 | ||
32 | int item_insert(struct radix_tree_root *root, unsigned long index) | 33 | int item_insert(struct radix_tree_root *root, unsigned long index) |
33 | { | 34 | { |
34 | return __item_insert(root, item_create(index)); | 35 | return __item_insert(root, item_create(index), 0); |
36 | } | ||
37 | |||
38 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | ||
39 | unsigned order) | ||
40 | { | ||
41 | return __item_insert(root, item_create(index), order); | ||
35 | } | 42 | } |
36 | 43 | ||
37 | int item_delete(struct radix_tree_root *root, unsigned long index) | 44 | int item_delete(struct radix_tree_root *root, unsigned long index) |
@@ -136,13 +143,13 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
136 | } | 143 | } |
137 | 144 | ||
138 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, | 145 | static int verify_node(struct radix_tree_node *slot, unsigned int tag, |
139 | unsigned int height, int tagged) | 146 | int tagged) |
140 | { | 147 | { |
141 | int anyset = 0; | 148 | int anyset = 0; |
142 | int i; | 149 | int i; |
143 | int j; | 150 | int j; |
144 | 151 | ||
145 | slot = indirect_to_ptr(slot); | 152 | slot = entry_to_node(slot); |
146 | 153 | ||
147 | /* Verify consistency at this level */ | 154 | /* Verify consistency at this level */ |
148 | for (i = 0; i < RADIX_TREE_TAG_LONGS; i++) { | 155 | for (i = 0; i < RADIX_TREE_TAG_LONGS; i++) { |
@@ -152,7 +159,8 @@ static int verify_node(struct radix_tree_node *slot, unsigned int tag, | |||
152 | } | 159 | } |
153 | } | 160 | } |
154 | if (tagged != anyset) { | 161 | if (tagged != anyset) { |
155 | printf("tag: %u, height %u, tagged: %d, anyset: %d\n", tag, height, tagged, anyset); | 162 | printf("tag: %u, shift %u, tagged: %d, anyset: %d\n", |
163 | tag, slot->shift, tagged, anyset); | ||
156 | for (j = 0; j < RADIX_TREE_MAX_TAGS; j++) { | 164 | for (j = 0; j < RADIX_TREE_MAX_TAGS; j++) { |
157 | printf("tag %d: ", j); | 165 | printf("tag %d: ", j); |
158 | for (i = 0; i < RADIX_TREE_TAG_LONGS; i++) | 166 | for (i = 0; i < RADIX_TREE_TAG_LONGS; i++) |
@@ -164,10 +172,10 @@ static int verify_node(struct radix_tree_node *slot, unsigned int tag, | |||
164 | assert(tagged == anyset); | 172 | assert(tagged == anyset); |
165 | 173 | ||
166 | /* Go for next level */ | 174 | /* Go for next level */ |
167 | if (height > 1) { | 175 | if (slot->shift > 0) { |
168 | for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) | 176 | for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) |
169 | if (slot->slots[i]) | 177 | if (slot->slots[i]) |
170 | if (verify_node(slot->slots[i], tag, height - 1, | 178 | if (verify_node(slot->slots[i], tag, |
171 | !!test_bit(i, slot->tags[tag]))) { | 179 | !!test_bit(i, slot->tags[tag]))) { |
172 | printf("Failure at off %d\n", i); | 180 | printf("Failure at off %d\n", i); |
173 | for (j = 0; j < RADIX_TREE_MAX_TAGS; j++) { | 181 | for (j = 0; j < RADIX_TREE_MAX_TAGS; j++) { |
@@ -184,9 +192,10 @@ static int verify_node(struct radix_tree_node *slot, unsigned int tag, | |||
184 | 192 | ||
185 | void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag) | 193 | void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag) |
186 | { | 194 | { |
187 | if (!root->height) | 195 | struct radix_tree_node *node = root->rnode; |
196 | if (!radix_tree_is_internal_node(node)) | ||
188 | return; | 197 | return; |
189 | verify_node(root->rnode, tag, root->height, !!root_tag_get(root, tag)); | 198 | verify_node(node, tag, !!root_tag_get(root, tag)); |
190 | } | 199 | } |
191 | 200 | ||
192 | void item_kill_tree(struct radix_tree_root *root) | 201 | void item_kill_tree(struct radix_tree_root *root) |
@@ -211,9 +220,19 @@ void item_kill_tree(struct radix_tree_root *root) | |||
211 | 220 | ||
212 | void tree_verify_min_height(struct radix_tree_root *root, int maxindex) | 221 | void tree_verify_min_height(struct radix_tree_root *root, int maxindex) |
213 | { | 222 | { |
214 | assert(radix_tree_maxindex(root->height) >= maxindex); | 223 | unsigned shift; |
215 | if (root->height > 1) | 224 | struct radix_tree_node *node = root->rnode; |
216 | assert(radix_tree_maxindex(root->height-1) < maxindex); | 225 | if (!radix_tree_is_internal_node(node)) { |
217 | else if (root->height == 1) | 226 | assert(maxindex == 0); |
218 | assert(radix_tree_maxindex(root->height-1) <= maxindex); | 227 | return; |
228 | } | ||
229 | |||
230 | node = entry_to_node(node); | ||
231 | assert(maxindex <= node_maxindex(node)); | ||
232 | |||
233 | shift = node->shift; | ||
234 | if (shift > 0) | ||
235 | assert(maxindex > shift_maxindex(shift - RADIX_TREE_MAP_SHIFT)); | ||
236 | else | ||
237 | assert(maxindex > 0); | ||
219 | } | 238 | } |
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h index 4e1d95faaa94..e85131369723 100644 --- a/tools/testing/radix-tree/test.h +++ b/tools/testing/radix-tree/test.h | |||
@@ -8,8 +8,11 @@ struct item { | |||
8 | }; | 8 | }; |
9 | 9 | ||
10 | struct item *item_create(unsigned long index); | 10 | struct item *item_create(unsigned long index); |
11 | int __item_insert(struct radix_tree_root *root, struct item *item); | 11 | int __item_insert(struct radix_tree_root *root, struct item *item, |
12 | unsigned order); | ||
12 | 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, | ||
15 | unsigned order); | ||
13 | int item_delete(struct radix_tree_root *root, unsigned long index); | 16 | int item_delete(struct radix_tree_root *root, unsigned long index); |
14 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index); | 17 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index); |
15 | 18 | ||
@@ -23,6 +26,7 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start, | |||
23 | void item_kill_tree(struct radix_tree_root *root); | 26 | void item_kill_tree(struct radix_tree_root *root); |
24 | 27 | ||
25 | void tag_check(void); | 28 | void tag_check(void); |
29 | void multiorder_checks(void); | ||
26 | 30 | ||
27 | struct item * | 31 | struct item * |
28 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); | 32 | item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); |
@@ -35,6 +39,7 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag); | |||
35 | extern int nr_allocated; | 39 | extern int nr_allocated; |
36 | 40 | ||
37 | /* Normally private parts of lib/radix-tree.c */ | 41 | /* Normally private parts of lib/radix-tree.c */ |
38 | void *indirect_to_ptr(void *ptr); | 42 | void radix_tree_dump(struct radix_tree_root *root); |
39 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); | 43 | int root_tag_get(struct radix_tree_root *root, unsigned int tag); |
40 | unsigned long radix_tree_maxindex(unsigned int height); | 44 | unsigned long node_maxindex(struct radix_tree_node *); |
45 | unsigned long shift_maxindex(unsigned int shift); | ||
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index da48812ab95e..4c6a0bf8ba79 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -88,7 +88,12 @@ parse_opts() { # opts | |||
88 | 88 | ||
89 | # Parameters | 89 | # Parameters |
90 | DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1` | 90 | DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1` |
91 | TRACING_DIR=$DEBUGFS_DIR/tracing | 91 | if [ -z "$DEBUGFS_DIR" ]; then |
92 | TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1` | ||
93 | else | ||
94 | TRACING_DIR=$DEBUGFS_DIR/tracing | ||
95 | fi | ||
96 | |||
92 | TOP_DIR=`absdir $0` | 97 | TOP_DIR=`absdir $0` |
93 | TEST_DIR=$TOP_DIR/test.d | 98 | TEST_DIR=$TOP_DIR/test.d |
94 | TEST_CASES=`find_testcases $TEST_DIR` | 99 | TEST_CASES=`find_testcases $TEST_DIR` |
@@ -102,7 +107,7 @@ parse_opts $* | |||
102 | [ $DEBUG -ne 0 ] && set -x | 107 | [ $DEBUG -ne 0 ] && set -x |
103 | 108 | ||
104 | # Verify parameters | 109 | # Verify parameters |
105 | if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then | 110 | if [ -z "$TRACING_DIR" -o ! -d "$TRACING_DIR" ]; then |
106 | errexit "No ftrace directory found" | 111 | errexit "No ftrace directory found" |
107 | fi | 112 | fi |
108 | 113 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc new file mode 100644 index 000000000000..d4ab27b522f8 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc | |||
@@ -0,0 +1,72 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event tracing - restricts events based on pid | ||
3 | |||
4 | do_reset() { | ||
5 | echo > set_event | ||
6 | echo > set_event_pid | ||
7 | echo 0 > options/event-fork | ||
8 | clear_trace | ||
9 | } | ||
10 | |||
11 | fail() { #msg | ||
12 | do_reset | ||
13 | echo $1 | ||
14 | exit $FAIL | ||
15 | } | ||
16 | |||
17 | yield() { | ||
18 | ping localhost -c 1 || sleep .001 || usleep 1 || sleep 1 | ||
19 | } | ||
20 | |||
21 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
22 | echo "event tracing is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | if [ ! -f set_event_pid ]; then | ||
27 | echo "event pid filtering is not supported" | ||
28 | exit_unsupported | ||
29 | fi | ||
30 | |||
31 | reset_tracer | ||
32 | do_reset | ||
33 | |||
34 | echo 1 > events/sched/sched_switch/enable | ||
35 | |||
36 | yield | ||
37 | |||
38 | count=`cat trace | grep sched_switch | wc -l` | ||
39 | if [ $count -eq 0 ]; then | ||
40 | fail "sched_switch events are not recorded" | ||
41 | fi | ||
42 | |||
43 | do_reset | ||
44 | |||
45 | read mypid rest < /proc/self/stat | ||
46 | |||
47 | echo $mypid > set_event_pid | ||
48 | echo 'sched:sched_switch' > set_event | ||
49 | |||
50 | yield | ||
51 | |||
52 | count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l` | ||
53 | if [ $count -ne 0 ]; then | ||
54 | fail "sched_switch events from other task are recorded" | ||
55 | fi | ||
56 | |||
57 | do_reset | ||
58 | |||
59 | echo $mypid > set_event_pid | ||
60 | echo 1 > options/event-fork | ||
61 | echo 1 > events/sched/sched_switch/enable | ||
62 | |||
63 | yield | ||
64 | |||
65 | count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l` | ||
66 | if [ $count -eq 0 ]; then | ||
67 | fail "sched_switch events from other task are not recorded" | ||
68 | fi | ||
69 | |||
70 | do_reset | ||
71 | |||
72 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index 5d8cd06d920f..c37262f6c269 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions | |||
@@ -14,3 +14,12 @@ enable_tracing() { # start trace recording | |||
14 | reset_tracer() { # reset the current tracer | 14 | reset_tracer() { # reset the current tracer |
15 | echo nop > current_tracer | 15 | echo nop > current_tracer |
16 | } | 16 | } |
17 | |||
18 | reset_trigger() { # reset all current setting triggers | ||
19 | grep -v ^# events/*/*/trigger | | ||
20 | while read line; do | ||
21 | cmd=`echo $line | cut -f2- -d: | cut -f1 -d" "` | ||
22 | echo "!$cmd" > `echo $line | cut -f1 -d:` | ||
23 | done | ||
24 | } | ||
25 | |||
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc new file mode 100644 index 000000000000..4c5a061a5b4e --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc | |||
@@ -0,0 +1,138 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Test creation and deletion of trace instances while setting an event | ||
3 | |||
4 | if [ ! -d instances ] ; then | ||
5 | echo "no instance directory with this kernel" | ||
6 | exit_unsupported; | ||
7 | fi | ||
8 | |||
9 | fail() { # mesg | ||
10 | rmdir foo 2>/dev/null | ||
11 | echo $1 | ||
12 | set -e | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | cd instances | ||
17 | |||
18 | # we don't want to fail on error | ||
19 | set +e | ||
20 | |||
21 | mkdir x | ||
22 | rmdir x | ||
23 | result=$? | ||
24 | |||
25 | if [ $result -ne 0 ]; then | ||
26 | echo "instance rmdir not supported" | ||
27 | exit_unsupported | ||
28 | fi | ||
29 | |||
30 | instance_slam() { | ||
31 | while :; do | ||
32 | mkdir foo 2> /dev/null | ||
33 | rmdir foo 2> /dev/null | ||
34 | done | ||
35 | } | ||
36 | |||
37 | instance_read() { | ||
38 | while :; do | ||
39 | cat foo/trace 1> /dev/null 2>&1 | ||
40 | done | ||
41 | } | ||
42 | |||
43 | instance_set() { | ||
44 | while :; do | ||
45 | echo 1 > foo/events/sched/sched_switch | ||
46 | done 2> /dev/null | ||
47 | } | ||
48 | |||
49 | instance_slam & | ||
50 | p1=$! | ||
51 | echo $p1 | ||
52 | |||
53 | instance_set & | ||
54 | p2=$! | ||
55 | echo $p2 | ||
56 | |||
57 | instance_read & | ||
58 | p3=$! | ||
59 | echo $p3 | ||
60 | |||
61 | sleep 1 | ||
62 | |||
63 | kill -1 $p3 | ||
64 | kill -1 $p2 | ||
65 | kill -1 $p1 | ||
66 | |||
67 | echo "Wait for processes to finish" | ||
68 | wait $p1 $p2 $p3 | ||
69 | echo "all processes finished, wait for cleanup" | ||
70 | sleep 1 | ||
71 | |||
72 | mkdir foo | ||
73 | ls foo > /dev/null | ||
74 | rmdir foo | ||
75 | if [ -d foo ]; then | ||
76 | fail "foo still exists" | ||
77 | fi | ||
78 | exit 0 | ||
79 | |||
80 | |||
81 | |||
82 | |||
83 | instance_slam() { | ||
84 | while :; do | ||
85 | mkdir x | ||
86 | mkdir y | ||
87 | mkdir z | ||
88 | rmdir x | ||
89 | rmdir y | ||
90 | rmdir z | ||
91 | done 2>/dev/null | ||
92 | } | ||
93 | |||
94 | instance_slam & | ||
95 | p1=$! | ||
96 | echo $p1 | ||
97 | |||
98 | instance_slam & | ||
99 | p2=$! | ||
100 | echo $p2 | ||
101 | |||
102 | instance_slam & | ||
103 | p3=$! | ||
104 | echo $p3 | ||
105 | |||
106 | instance_slam & | ||
107 | p4=$! | ||
108 | echo $p4 | ||
109 | |||
110 | instance_slam & | ||
111 | p5=$! | ||
112 | echo $p5 | ||
113 | |||
114 | ls -lR >/dev/null | ||
115 | sleep 1 | ||
116 | |||
117 | kill -1 $p1 | ||
118 | kill -1 $p2 | ||
119 | kill -1 $p3 | ||
120 | kill -1 $p4 | ||
121 | kill -1 $p5 | ||
122 | |||
123 | echo "Wait for processes to finish" | ||
124 | wait $p1 $p2 $p3 $p4 $p5 | ||
125 | echo "all processes finished, wait for cleanup" | ||
126 | |||
127 | mkdir x y z | ||
128 | ls x y z | ||
129 | rmdir x y z | ||
130 | for d in x y z; do | ||
131 | if [ -d $d ]; then | ||
132 | fail "instance $d still exists" | ||
133 | fi | ||
134 | done | ||
135 | |||
136 | set -e | ||
137 | |||
138 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc new file mode 100644 index 000000000000..1a9445021bf1 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc | |||
@@ -0,0 +1,64 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test event enable/disable trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep enable_event events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "event enable/disable trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | echo "Test enable_event trigger" | ||
36 | echo 0 > events/sched/sched_switch/enable | ||
37 | echo 'enable_event:sched:sched_switch' > events/sched/sched_process_fork/trigger | ||
38 | ( echo "forked") | ||
39 | if [ `cat events/sched/sched_switch/enable` != '1*' ]; then | ||
40 | fail "enable_event trigger on sched_process_fork did not work" | ||
41 | fi | ||
42 | |||
43 | reset_trigger | ||
44 | |||
45 | echo "Test disable_event trigger" | ||
46 | echo 1 > events/sched/sched_switch/enable | ||
47 | echo 'disable_event:sched:sched_switch' > events/sched/sched_process_fork/trigger | ||
48 | ( echo "forked") | ||
49 | if [ `cat events/sched/sched_switch/enable` != '0*' ]; then | ||
50 | fail "disable_event trigger on sched_process_fork did not work" | ||
51 | fi | ||
52 | |||
53 | reset_trigger | ||
54 | |||
55 | echo "Test semantic error for event enable/disable trigger" | ||
56 | ! echo 'enable_event:nogroup:noevent' > events/sched/sched_process_fork/trigger | ||
57 | ! echo 'disable_event+1' > events/sched/sched_process_fork/trigger | ||
58 | echo 'enable_event:sched:sched_switch' > events/sched/sched_process_fork/trigger | ||
59 | ! echo 'enable_event:sched:sched_switch' > events/sched/sched_process_fork/trigger | ||
60 | ! echo 'disable_event:sched:sched_switch' > events/sched/sched_process_fork/trigger | ||
61 | |||
62 | do_reset | ||
63 | |||
64 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc new file mode 100644 index 000000000000..514e466e198b --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc | |||
@@ -0,0 +1,59 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test trigger filter | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | echo "Test trigger filter" | ||
30 | echo 1 > tracing_on | ||
31 | echo 'traceoff if child_pid == 0' > events/sched/sched_process_fork/trigger | ||
32 | ( echo "forked") | ||
33 | if [ `cat tracing_on` -ne 1 ]; then | ||
34 | fail "traceoff trigger on sched_process_fork did not work" | ||
35 | fi | ||
36 | |||
37 | reset_trigger | ||
38 | |||
39 | echo "Test semantic error for trigger filter" | ||
40 | ! echo 'traceoff if a' > events/sched/sched_process_fork/trigger | ||
41 | ! echo 'traceoff if common_pid=0' > events/sched/sched_process_fork/trigger | ||
42 | ! echo 'traceoff if common_pid==b' > events/sched/sched_process_fork/trigger | ||
43 | echo 'traceoff if common_pid == 0' > events/sched/sched_process_fork/trigger | ||
44 | echo '!traceoff' > events/sched/sched_process_fork/trigger | ||
45 | ! echo 'traceoff if common_pid == child_pid' > events/sched/sched_process_fork/trigger | ||
46 | echo 'traceoff if common_pid <= 0' > events/sched/sched_process_fork/trigger | ||
47 | echo '!traceoff' > events/sched/sched_process_fork/trigger | ||
48 | echo 'traceoff if common_pid >= 0' > events/sched/sched_process_fork/trigger | ||
49 | echo '!traceoff' > events/sched/sched_process_fork/trigger | ||
50 | echo 'traceoff if parent_pid >= 0 && child_pid >= 0' > events/sched/sched_process_fork/trigger | ||
51 | echo '!traceoff' > events/sched/sched_process_fork/trigger | ||
52 | echo 'traceoff if parent_pid >= 0 || child_pid >= 0' > events/sched/sched_process_fork/trigger | ||
53 | echo '!traceoff' > events/sched/sched_process_fork/trigger | ||
54 | |||
55 | |||
56 | |||
57 | do_reset | ||
58 | |||
59 | 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 new file mode 100644 index 000000000000..c2b61c4fda11 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc | |||
@@ -0,0 +1,75 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test histogram modifiers | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep hist events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "hist trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | echo "Test histogram with execname modifier" | ||
36 | |||
37 | echo 'hist:keys=common_pid.execname' > events/sched/sched_process_fork/trigger | ||
38 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
39 | COMM=`cat /proc/$$/comm` | ||
40 | grep "common_pid: $COMM" events/sched/sched_process_fork/hist > /dev/null || \ | ||
41 | fail "execname modifier on sched_process_fork did not work" | ||
42 | |||
43 | reset_trigger | ||
44 | |||
45 | echo "Test histogram with hex modifier" | ||
46 | |||
47 | echo 'hist:keys=parent_pid.hex' > events/sched/sched_process_fork/trigger | ||
48 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
49 | # Note that $$ is the parent pid. $PID is current PID. | ||
50 | HEX=`printf %x $PID` | ||
51 | grep "parent_pid: $HEX" events/sched/sched_process_fork/hist > /dev/null || \ | ||
52 | fail "hex modifier on sched_process_fork did not work" | ||
53 | |||
54 | reset_trigger | ||
55 | |||
56 | echo "Test histogram with syscall modifier" | ||
57 | |||
58 | echo 'hist:keys=id.syscall' > events/raw_syscalls/sys_exit/trigger | ||
59 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
60 | grep "id: sys_" events/raw_syscalls/sys_exit/hist > /dev/null || \ | ||
61 | fail "syscall modifier on raw_syscalls/sys_exit did not work" | ||
62 | |||
63 | |||
64 | reset_trigger | ||
65 | |||
66 | echo "Test histgram with log2 modifier" | ||
67 | |||
68 | echo 'hist:keys=bytes_req.log2' > events/kmem/kmalloc/trigger | ||
69 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
70 | grep 'bytes_req: ~ 2^[0-9]*' events/kmem/kmalloc/hist > /dev/null || \ | ||
71 | fail "log2 modifier on kmem/kmalloc did not work" | ||
72 | |||
73 | do_reset | ||
74 | |||
75 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc new file mode 100644 index 000000000000..b2902d42a537 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc | |||
@@ -0,0 +1,83 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test histogram trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep hist events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "hist trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | echo "Test histogram basic tigger" | ||
36 | |||
37 | echo 'hist:keys=parent_pid:vals=child_pid' > events/sched/sched_process_fork/trigger | ||
38 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
39 | grep parent_pid events/sched/sched_process_fork/hist > /dev/null || \ | ||
40 | fail "hist trigger on sched_process_fork did not work" | ||
41 | grep child events/sched/sched_process_fork/hist > /dev/null || \ | ||
42 | fail "hist trigger on sched_process_fork did not work" | ||
43 | |||
44 | reset_trigger | ||
45 | |||
46 | echo "Test histogram with compound keys" | ||
47 | |||
48 | echo 'hist:keys=parent_pid,child_pid' > events/sched/sched_process_fork/trigger | ||
49 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
50 | grep '^{ parent_pid:.*, child_pid:.*}' events/sched/sched_process_fork/hist > /dev/null || \ | ||
51 | fail "compound keys on sched_process_fork did not work" | ||
52 | |||
53 | reset_trigger | ||
54 | |||
55 | echo "Test histogram with string key" | ||
56 | |||
57 | echo 'hist:keys=parent_comm' > events/sched/sched_process_fork/trigger | ||
58 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
59 | COMM=`cat /proc/$$/comm` | ||
60 | grep "parent_comm: $COMM" events/sched/sched_process_fork/hist > /dev/null || \ | ||
61 | fail "string key on sched_process_fork did not work" | ||
62 | |||
63 | reset_trigger | ||
64 | |||
65 | echo "Test histogram with sort key" | ||
66 | |||
67 | echo 'hist:keys=parent_pid,child_pid:sort=child_pid.ascending' > events/sched/sched_process_fork/trigger | ||
68 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
69 | |||
70 | check_inc() { | ||
71 | while [ $# -gt 1 ]; do | ||
72 | [ $1 -gt $2 ] && return 1 | ||
73 | shift 1 | ||
74 | done | ||
75 | return 0 | ||
76 | } | ||
77 | check_inc `grep -o "child_pid:[[:space:]]*[[:digit:]]*" \ | ||
78 | events/sched/sched_process_fork/hist | cut -d: -f2 ` || | ||
79 | fail "sort param on sched_process_fork did not work" | ||
80 | |||
81 | do_reset | ||
82 | |||
83 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc new file mode 100644 index 000000000000..03c4a46561fc --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc | |||
@@ -0,0 +1,73 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test multiple histogram triggers | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep hist events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "hist trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | reset_trigger | ||
36 | |||
37 | echo "Test histogram multiple tiggers" | ||
38 | |||
39 | echo 'hist:keys=parent_pid:vals=child_pid' > events/sched/sched_process_fork/trigger | ||
40 | echo 'hist:keys=parent_comm:vals=child_pid' >> events/sched/sched_process_fork/trigger | ||
41 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
42 | grep parent_pid events/sched/sched_process_fork/hist > /dev/null || \ | ||
43 | fail "hist trigger on sched_process_fork did not work" | ||
44 | grep child events/sched/sched_process_fork/hist > /dev/null || \ | ||
45 | fail "hist trigger on sched_process_fork did not work" | ||
46 | COMM=`cat /proc/$$/comm` | ||
47 | grep "parent_comm: $COMM" events/sched/sched_process_fork/hist > /dev/null || \ | ||
48 | fail "string key on sched_process_fork did not work" | ||
49 | |||
50 | reset_trigger | ||
51 | |||
52 | echo "Test histogram with its name" | ||
53 | |||
54 | echo 'hist:name=test_hist:keys=common_pid' > events/sched/sched_process_fork/trigger | ||
55 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
56 | grep test_hist events/sched/sched_process_fork/hist > /dev/null || \ | ||
57 | fail "named event on sched_process_fork did not work" | ||
58 | |||
59 | echo "Test same named histogram on different events" | ||
60 | |||
61 | echo 'hist:name=test_hist:keys=common_pid' > events/sched/sched_process_exit/trigger | ||
62 | for i in `seq 1 10` ; do ( echo "forked" > /dev/null); done | ||
63 | grep test_hist events/sched/sched_process_exit/hist > /dev/null || \ | ||
64 | fail "named event on sched_process_fork did not work" | ||
65 | |||
66 | diffs=`diff events/sched/sched_process_exit/hist events/sched/sched_process_fork/hist | wc -l` | ||
67 | test $diffs -eq 0 || fail "Same name histograms are not same" | ||
68 | |||
69 | reset_trigger | ||
70 | |||
71 | do_reset | ||
72 | |||
73 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc new file mode 100644 index 000000000000..f84b80d551a2 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc | |||
@@ -0,0 +1,56 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test snapshot-trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep snapshot events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "snapshot trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | echo "Test snapshot tigger" | ||
36 | echo 0 > snapshot | ||
37 | echo 1 > events/sched/sched_process_fork/enable | ||
38 | ( echo "forked") | ||
39 | echo 'snapshot:1' > events/sched/sched_process_fork/trigger | ||
40 | ( echo "forked") | ||
41 | grep sched_process_fork snapshot > /dev/null || \ | ||
42 | fail "snapshot trigger on sched_process_fork did not work" | ||
43 | |||
44 | reset_trigger | ||
45 | echo 0 > snapshot | ||
46 | echo 0 > events/sched/sched_process_fork/enable | ||
47 | |||
48 | echo "Test snapshot semantic errors" | ||
49 | |||
50 | ! echo "snapshot+1" > events/sched/sched_process_fork/trigger | ||
51 | echo "snapshot" > events/sched/sched_process_fork/trigger | ||
52 | ! echo "snapshot" > events/sched/sched_process_fork/trigger | ||
53 | |||
54 | do_reset | ||
55 | |||
56 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc new file mode 100644 index 000000000000..9fa23b085def --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-stacktrace.tc | |||
@@ -0,0 +1,53 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test stacktrace-trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | FEATURE=`grep stacktrace events/sched/sched_process_fork/trigger` | ||
30 | if [ -z "$FEATURE" ]; then | ||
31 | echo "stacktrace trigger is not supported" | ||
32 | exit_unsupported | ||
33 | fi | ||
34 | |||
35 | echo "Test stacktrace tigger" | ||
36 | echo 0 > trace | ||
37 | echo 0 > options/stacktrace | ||
38 | echo 'stacktrace' > events/sched/sched_process_fork/trigger | ||
39 | ( echo "forked") | ||
40 | grep "<stack trace>" trace > /dev/null || \ | ||
41 | fail "stacktrace trigger on sched_process_fork did not work" | ||
42 | |||
43 | reset_trigger | ||
44 | |||
45 | echo "Test stacktrace semantic errors" | ||
46 | |||
47 | ! echo "stacktrace:foo" > events/sched/sched_process_fork/trigger | ||
48 | echo "stacktrace" > events/sched/sched_process_fork/trigger | ||
49 | ! echo "stacktrace" > events/sched/sched_process_fork/trigger | ||
50 | |||
51 | do_reset | ||
52 | |||
53 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc new file mode 100644 index 000000000000..87648e5f987c --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-traceonoff.tc | |||
@@ -0,0 +1,58 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test traceon/off trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit $FAIL | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event -o ! -d events/sched ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f events/sched/sched_process_fork/trigger ]; then | ||
22 | echo "event trigger is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | echo "Test traceoff trigger" | ||
30 | echo 1 > tracing_on | ||
31 | echo 'traceoff' > events/sched/sched_process_fork/trigger | ||
32 | ( echo "forked") | ||
33 | if [ `cat tracing_on` -ne 0 ]; then | ||
34 | fail "traceoff trigger on sched_process_fork did not work" | ||
35 | fi | ||
36 | |||
37 | reset_trigger | ||
38 | |||
39 | echo "Test traceon trigger" | ||
40 | echo 0 > tracing_on | ||
41 | echo 'traceon' > events/sched/sched_process_fork/trigger | ||
42 | ( echo "forked") | ||
43 | if [ `cat tracing_on` -ne 1 ]; then | ||
44 | fail "traceoff trigger on sched_process_fork did not work" | ||
45 | fi | ||
46 | |||
47 | reset_trigger | ||
48 | |||
49 | echo "Test semantic error for traceoff/on trigger" | ||
50 | ! echo 'traceoff:badparam' > events/sched/sched_process_fork/trigger | ||
51 | ! echo 'traceoff+0' > events/sched/sched_process_fork/trigger | ||
52 | echo 'traceon' > events/sched/sched_process_fork/trigger | ||
53 | ! echo 'traceon' > events/sched/sched_process_fork/trigger | ||
54 | ! echo 'traceoff' > events/sched/sched_process_fork/trigger | ||
55 | |||
56 | do_reset | ||
57 | |||
58 | exit 0 | ||
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index bdaf37e92684..7868c106b8b1 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh | |||
@@ -32,7 +32,7 @@ EVALUATE_ONLY=0 | |||
32 | max_cpus=$(($(nproc)-1)) | 32 | max_cpus=$(($(nproc)-1)) |
33 | 33 | ||
34 | # compile programs | 34 | # compile programs |
35 | gcc -o aperf aperf.c -lm | 35 | gcc aperf.c -Wall -D_GNU_SOURCE -o aperf -lm |
36 | [ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 | 36 | [ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 |
37 | gcc -o msr msr.c -lm | 37 | gcc -o msr msr.c -lm |
38 | [ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 | 38 | [ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 |
diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c index 96ba386b1b7b..4a8217448f20 100644 --- a/tools/testing/selftests/net/reuseport_bpf.c +++ b/tools/testing/selftests/net/reuseport_bpf.c | |||
@@ -111,9 +111,9 @@ static void attach_ebpf(int fd, uint16_t mod) | |||
111 | memset(&attr, 0, sizeof(attr)); | 111 | memset(&attr, 0, sizeof(attr)); |
112 | attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; | 112 | attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; |
113 | attr.insn_cnt = ARRAY_SIZE(prog); | 113 | attr.insn_cnt = ARRAY_SIZE(prog); |
114 | attr.insns = (uint64_t)prog; | 114 | attr.insns = (unsigned long) &prog; |
115 | attr.license = (uint64_t)bpf_license; | 115 | attr.license = (unsigned long) &bpf_license; |
116 | attr.log_buf = (uint64_t)bpf_log_buf; | 116 | attr.log_buf = (unsigned long) &bpf_log_buf; |
117 | attr.log_size = sizeof(bpf_log_buf); | 117 | attr.log_size = sizeof(bpf_log_buf); |
118 | attr.log_level = 1; | 118 | attr.log_level = 1; |
119 | attr.kern_version = 0; | 119 | attr.kern_version = 0; |
@@ -351,8 +351,8 @@ static void test_filter_no_reuseport(const struct test_params p) | |||
351 | memset(&eprog, 0, sizeof(eprog)); | 351 | memset(&eprog, 0, sizeof(eprog)); |
352 | eprog.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; | 352 | eprog.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; |
353 | eprog.insn_cnt = ARRAY_SIZE(ecode); | 353 | eprog.insn_cnt = ARRAY_SIZE(ecode); |
354 | eprog.insns = (uint64_t)ecode; | 354 | eprog.insns = (unsigned long) &ecode; |
355 | eprog.license = (uint64_t)bpf_license; | 355 | eprog.license = (unsigned long) &bpf_license; |
356 | eprog.kern_version = 0; | 356 | eprog.kern_version = 0; |
357 | 357 | ||
358 | memset(&cprog, 0, sizeof(cprog)); | 358 | memset(&cprog, 0, sizeof(cprog)); |
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index b08f77cbe31b..4ca83fe80654 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile | |||
@@ -14,6 +14,7 @@ export CFLAGS | |||
14 | 14 | ||
15 | SUB_DIRS = benchmarks \ | 15 | SUB_DIRS = benchmarks \ |
16 | copyloops \ | 16 | copyloops \ |
17 | context_switch \ | ||
17 | dscr \ | 18 | dscr \ |
18 | mm \ | 19 | mm \ |
19 | pmu \ | 20 | pmu \ |
diff --git a/tools/testing/selftests/powerpc/context_switch/.gitignore b/tools/testing/selftests/powerpc/context_switch/.gitignore new file mode 100644 index 000000000000..c1431af7b51c --- /dev/null +++ b/tools/testing/selftests/powerpc/context_switch/.gitignore | |||
@@ -0,0 +1 @@ | |||
cp_abort | |||
diff --git a/tools/testing/selftests/powerpc/context_switch/Makefile b/tools/testing/selftests/powerpc/context_switch/Makefile new file mode 100644 index 000000000000..e164d1466466 --- /dev/null +++ b/tools/testing/selftests/powerpc/context_switch/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | TEST_PROGS := cp_abort | ||
2 | |||
3 | all: $(TEST_PROGS) | ||
4 | |||
5 | $(TEST_PROGS): ../harness.c ../utils.c | ||
6 | |||
7 | include ../../lib.mk | ||
8 | |||
9 | clean: | ||
10 | rm -f $(TEST_PROGS) | ||
diff --git a/tools/testing/selftests/powerpc/context_switch/cp_abort.c b/tools/testing/selftests/powerpc/context_switch/cp_abort.c new file mode 100644 index 000000000000..5a5b55afda0e --- /dev/null +++ b/tools/testing/selftests/powerpc/context_switch/cp_abort.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Adapted from Anton Blanchard's context switch microbenchmark. | ||
3 | * | ||
4 | * Copyright 2009, Anton Blanchard, IBM Corporation. | ||
5 | * Copyright 2016, Mikey Neuling, Chris Smart, IBM Corporation. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program tests the copy paste abort functionality of a P9 | ||
13 | * (or later) by setting up two processes on the same CPU, one | ||
14 | * which executes the copy instruction and the other which | ||
15 | * executes paste. | ||
16 | * | ||
17 | * The paste instruction should never succeed, as the cp_abort | ||
18 | * instruction is called by the kernel during a context switch. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define _GNU_SOURCE | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <unistd.h> | ||
26 | #include <stdlib.h> | ||
27 | #include "utils.h" | ||
28 | #include <sched.h> | ||
29 | |||
30 | #define READ_FD 0 | ||
31 | #define WRITE_FD 1 | ||
32 | |||
33 | #define NUM_LOOPS 1000 | ||
34 | |||
35 | /* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */ | ||
36 | #define PASTE(RA, RB, L, RC) \ | ||
37 | .long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31)) | ||
38 | |||
39 | int paste(void *i) | ||
40 | { | ||
41 | int cr; | ||
42 | |||
43 | asm volatile(str(PASTE(0, %1, 1, 1))";" | ||
44 | "mfcr %0;" | ||
45 | : "=r" (cr) | ||
46 | : "b" (i) | ||
47 | : "memory" | ||
48 | ); | ||
49 | return cr; | ||
50 | } | ||
51 | |||
52 | /* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */ | ||
53 | #define COPY(RA, RB, L) \ | ||
54 | .long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10)) | ||
55 | |||
56 | void copy(void *i) | ||
57 | { | ||
58 | asm volatile(str(COPY(0, %0, 1))";" | ||
59 | : | ||
60 | : "b" (i) | ||
61 | : "memory" | ||
62 | ); | ||
63 | } | ||
64 | |||
65 | int test_cp_abort(void) | ||
66 | { | ||
67 | /* 128 bytes for a full cache line */ | ||
68 | char buf[128] __cacheline_aligned; | ||
69 | cpu_set_t cpuset; | ||
70 | int fd1[2], fd2[2], pid; | ||
71 | char c; | ||
72 | |||
73 | /* only run this test on a P9 or later */ | ||
74 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00)); | ||
75 | |||
76 | /* | ||
77 | * Run both processes on the same CPU, so that copy is more likely | ||
78 | * to leak into a paste. | ||
79 | */ | ||
80 | CPU_ZERO(&cpuset); | ||
81 | CPU_SET(pick_online_cpu(), &cpuset); | ||
82 | FAIL_IF(sched_setaffinity(0, sizeof(cpuset), &cpuset)); | ||
83 | |||
84 | FAIL_IF(pipe(fd1) || pipe(fd2)); | ||
85 | |||
86 | pid = fork(); | ||
87 | FAIL_IF(pid < 0); | ||
88 | |||
89 | if (!pid) { | ||
90 | for (int i = 0; i < NUM_LOOPS; i++) { | ||
91 | FAIL_IF((write(fd1[WRITE_FD], &c, 1)) != 1); | ||
92 | FAIL_IF((read(fd2[READ_FD], &c, 1)) != 1); | ||
93 | /* A paste succeeds if CR0 EQ bit is set */ | ||
94 | FAIL_IF(paste(buf) & 0x20000000); | ||
95 | } | ||
96 | } else { | ||
97 | for (int i = 0; i < NUM_LOOPS; i++) { | ||
98 | FAIL_IF((read(fd1[READ_FD], &c, 1)) != 1); | ||
99 | copy(buf); | ||
100 | FAIL_IF((write(fd2[WRITE_FD], &c, 1) != 1)); | ||
101 | } | ||
102 | } | ||
103 | return 0; | ||
104 | |||
105 | } | ||
106 | |||
107 | int main(int argc, char *argv[]) | ||
108 | { | ||
109 | return test_harness(test_cp_abort, "cp_abort"); | ||
110 | } | ||
diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c index 440180ff8089..35ade7406dcd 100644 --- a/tools/testing/selftests/powerpc/mm/subpage_prot.c +++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c | |||
@@ -73,7 +73,7 @@ static inline void check_faulted(void *addr, long page, long subpage, int write) | |||
73 | want_fault |= (subpage == ((page + 1) % 16)); | 73 | want_fault |= (subpage == ((page + 1) % 16)); |
74 | 74 | ||
75 | if (faulted != want_fault) { | 75 | if (faulted != want_fault) { |
76 | printf("Failed at 0x%p (p=%ld,sp=%ld,w=%d), want=%s, got=%s !\n", | 76 | printf("Failed at %p (p=%ld,sp=%ld,w=%d), want=%s, got=%s !\n", |
77 | addr, page, subpage, write, | 77 | addr, page, subpage, write, |
78 | want_fault ? "fault" : "pass", | 78 | want_fault ? "fault" : "pass", |
79 | faulted ? "fault" : "pass"); | 79 | faulted ? "fault" : "pass"); |
@@ -82,7 +82,7 @@ static inline void check_faulted(void *addr, long page, long subpage, int write) | |||
82 | 82 | ||
83 | if (faulted) { | 83 | if (faulted) { |
84 | if (dar != addr) { | 84 | if (dar != addr) { |
85 | printf("Fault expected at 0x%p and happened at 0x%p !\n", | 85 | printf("Fault expected at %p and happened at %p !\n", |
86 | addr, dar); | 86 | addr, dar); |
87 | } | 87 | } |
88 | faulted = 0; | 88 | faulted = 0; |
@@ -162,7 +162,7 @@ int test_anon(void) | |||
162 | 162 | ||
163 | mallocblock = (void *)align; | 163 | mallocblock = (void *)align; |
164 | 164 | ||
165 | printf("allocated malloc block of 0x%lx bytes at 0x%p\n", | 165 | printf("allocated malloc block of 0x%lx bytes at %p\n", |
166 | mallocsize, mallocblock); | 166 | mallocsize, mallocblock); |
167 | 167 | ||
168 | printf("testing malloc block...\n"); | 168 | printf("testing malloc block...\n"); |
@@ -197,7 +197,7 @@ int test_file(void) | |||
197 | perror("failed to map file"); | 197 | perror("failed to map file"); |
198 | return 1; | 198 | return 1; |
199 | } | 199 | } |
200 | printf("allocated %s for 0x%lx bytes at 0x%p\n", | 200 | printf("allocated %s for 0x%lx bytes at %p\n", |
201 | file_name, filesize, fileblock); | 201 | file_name, filesize, fileblock); |
202 | 202 | ||
203 | printf("testing file map...\n"); | 203 | printf("testing file map...\n"); |
@@ -207,14 +207,16 @@ int test_file(void) | |||
207 | 207 | ||
208 | int main(int argc, char *argv[]) | 208 | int main(int argc, char *argv[]) |
209 | { | 209 | { |
210 | test_harness(test_anon, "subpage_prot_anon"); | 210 | int rc; |
211 | |||
212 | rc = test_harness(test_anon, "subpage_prot_anon"); | ||
213 | if (rc) | ||
214 | return rc; | ||
211 | 215 | ||
212 | if (argc > 1) | 216 | if (argc > 1) |
213 | file_name = argv[1]; | 217 | file_name = argv[1]; |
214 | else | 218 | else |
215 | file_name = "tempfile"; | 219 | file_name = "tempfile"; |
216 | 220 | ||
217 | test_harness(test_file, "subpage_prot_file"); | 221 | return test_harness(test_file, "subpage_prot_file"); |
218 | |||
219 | return 0; | ||
220 | } | 222 | } |
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c index e67452f1bcff..46681fec549b 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <sys/ioctl.h> | 15 | #include <sys/ioctl.h> |
16 | 16 | ||
17 | #include "trace.h" | 17 | #include "trace.h" |
18 | #include "reg.h" | ||
19 | #include "ebb.h" | 18 | #include "ebb.h" |
20 | 19 | ||
21 | 20 | ||
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c index 5b1188f10c15..f923228bca22 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | 8 | ||
9 | #include "ebb.h" | 9 | #include "ebb.h" |
10 | #include "reg.h" | ||
11 | 10 | ||
12 | 11 | ||
13 | /* | 12 | /* |
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg.h b/tools/testing/selftests/powerpc/reg.h index 5921b0dfe2e9..65bfdeeebdee 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/reg.h +++ b/tools/testing/selftests/powerpc/reg.h | |||
@@ -9,12 +9,12 @@ | |||
9 | #define __stringify_1(x) #x | 9 | #define __stringify_1(x) #x |
10 | #define __stringify(x) __stringify_1(x) | 10 | #define __stringify(x) __stringify_1(x) |
11 | 11 | ||
12 | #define mfspr(rn) ({unsigned long rval; \ | 12 | #define mfspr(rn) ({unsigned long rval; \ |
13 | asm volatile("mfspr %0," __stringify(rn) \ | 13 | asm volatile("mfspr %0," _str(rn) \ |
14 | : "=r" (rval)); rval; }) | 14 | : "=r" (rval)); rval; }) |
15 | #define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : \ | 15 | #define mtspr(rn, v) asm volatile("mtspr " _str(rn) ",%0" : \ |
16 | : "r" ((unsigned long)(v)) \ | 16 | : "r" ((unsigned long)(v)) \ |
17 | : "memory") | 17 | : "memory") |
18 | 18 | ||
19 | #define mb() asm volatile("sync" : : : "memory"); | 19 | #define mb() asm volatile("sync" : : : "memory"); |
20 | 20 | ||
@@ -46,4 +46,10 @@ | |||
46 | #define SPRN_SDAR 781 | 46 | #define SPRN_SDAR 781 |
47 | #define SPRN_SIER 768 | 47 | #define SPRN_SIER 768 |
48 | 48 | ||
49 | #define SPRN_TEXASR 0x82 | ||
50 | #define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */ | ||
51 | #define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */ | ||
52 | #define TEXASR_FS 0x08000000 | ||
53 | #define SPRN_TAR 0x32f | ||
54 | |||
49 | #endif /* _SELFTESTS_POWERPC_REG_H */ | 55 | #endif /* _SELFTESTS_POWERPC_REG_H */ |
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 7d0f14b8cb2e..bb942db845bf 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore | |||
@@ -3,3 +3,6 @@ tm-syscall | |||
3 | tm-signal-msr-resv | 3 | tm-signal-msr-resv |
4 | tm-signal-stack | 4 | tm-signal-stack |
5 | tm-vmxcopy | 5 | tm-vmxcopy |
6 | tm-fork | ||
7 | tm-tar | ||
8 | tm-tmspr | ||
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 737f72c964e6..d0505dbd22d5 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy | 1 | TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy tm-fork tm-tar tm-tmspr |
2 | 2 | ||
3 | all: $(TEST_PROGS) | 3 | all: $(TEST_PROGS) |
4 | 4 | ||
@@ -6,6 +6,7 @@ $(TEST_PROGS): ../harness.c ../utils.c | |||
6 | 6 | ||
7 | tm-syscall: tm-syscall-asm.S | 7 | tm-syscall: tm-syscall-asm.S |
8 | tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include | 8 | tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include |
9 | tm-tmspr: CFLAGS += -pthread | ||
9 | 10 | ||
10 | include ../../lib.mk | 11 | include ../../lib.mk |
11 | 12 | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-fork.c b/tools/testing/selftests/powerpc/tm/tm-fork.c new file mode 100644 index 000000000000..8d48579b7778 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-fork.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Edited: Rashmica Gupta, Nov 2015 | ||
6 | * | ||
7 | * This test does a fork syscall inside a transaction. Basic sniff test | ||
8 | * to see if we can enter the kernel during a transaction. | ||
9 | */ | ||
10 | |||
11 | #include <errno.h> | ||
12 | #include <inttypes.h> | ||
13 | #include <pthread.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | |||
18 | #include "utils.h" | ||
19 | #include "tm.h" | ||
20 | |||
21 | int test_fork(void) | ||
22 | { | ||
23 | SKIP_IF(!have_htm()); | ||
24 | |||
25 | asm __volatile__( | ||
26 | "tbegin.;" | ||
27 | "blt 1f; " | ||
28 | "li 0, 2;" /* fork syscall */ | ||
29 | "sc ;" | ||
30 | "tend.;" | ||
31 | "1: ;" | ||
32 | : : : "memory", "r0"); | ||
33 | /* If we reach here, we've passed. Otherwise we've probably crashed | ||
34 | * the kernel */ | ||
35 | |||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | int main(int argc, char *argv[]) | ||
40 | { | ||
41 | return test_harness(test_fork, "tm_fork"); | ||
42 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index 8fde93d6021f..d9c49f41515e 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | |||
@@ -31,12 +31,6 @@ | |||
31 | #include "utils.h" | 31 | #include "utils.h" |
32 | #include "tm.h" | 32 | #include "tm.h" |
33 | 33 | ||
34 | #define TBEGIN ".long 0x7C00051D ;" | ||
35 | #define TEND ".long 0x7C00055D ;" | ||
36 | #define TCHECK ".long 0x7C00059C ;" | ||
37 | #define TSUSPEND ".long 0x7C0005DD ;" | ||
38 | #define TRESUME ".long 0x7C2005DD ;" | ||
39 | #define SPRN_TEXASR 0x82 | ||
40 | #define SPRN_DSCR 0x03 | 34 | #define SPRN_DSCR 0x03 |
41 | 35 | ||
42 | int test_body(void) | 36 | int test_body(void) |
@@ -55,13 +49,13 @@ int test_body(void) | |||
55 | "mtspr %[sprn_dscr], 3;" | 49 | "mtspr %[sprn_dscr], 3;" |
56 | 50 | ||
57 | /* start and suspend a transaction */ | 51 | /* start and suspend a transaction */ |
58 | TBEGIN | 52 | "tbegin.;" |
59 | "beq 1f;" | 53 | "beq 1f;" |
60 | TSUSPEND | 54 | "tsuspend.;" |
61 | 55 | ||
62 | /* hard loop until the transaction becomes doomed */ | 56 | /* hard loop until the transaction becomes doomed */ |
63 | "2: ;" | 57 | "2: ;" |
64 | TCHECK | 58 | "tcheck 0;" |
65 | "bc 4, 0, 2b;" | 59 | "bc 4, 0, 2b;" |
66 | 60 | ||
67 | /* record DSCR and TEXASR */ | 61 | /* record DSCR and TEXASR */ |
@@ -70,8 +64,8 @@ int test_body(void) | |||
70 | "mfspr 3, %[sprn_texasr];" | 64 | "mfspr 3, %[sprn_texasr];" |
71 | "std 3, %[texasr];" | 65 | "std 3, %[texasr];" |
72 | 66 | ||
73 | TRESUME | 67 | "tresume.;" |
74 | TEND | 68 | "tend.;" |
75 | "li %[rv], 0;" | 69 | "li %[rv], 0;" |
76 | "1: ;" | 70 | "1: ;" |
77 | : [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr) | 71 | : [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr) |
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c index e44a238c1d77..1f0eb567438d 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c | |||
@@ -60,9 +60,9 @@ int tm_signal_stack() | |||
60 | exit(1); | 60 | exit(1); |
61 | asm volatile("li 1, 0 ;" /* stack ptr == NULL */ | 61 | asm volatile("li 1, 0 ;" /* stack ptr == NULL */ |
62 | "1:" | 62 | "1:" |
63 | ".long 0x7C00051D ;" /* tbegin */ | 63 | "tbegin.;" |
64 | "beq 1b ;" /* retry forever */ | 64 | "beq 1b ;" /* retry forever */ |
65 | ".long 0x7C0005DD ; ;" /* tsuspend */ | 65 | "tsuspend.;" |
66 | "ld 2, 0(1) ;" /* trigger segv" */ | 66 | "ld 2, 0(1) ;" /* trigger segv" */ |
67 | : : : "memory"); | 67 | : : : "memory"); |
68 | 68 | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-tar.c b/tools/testing/selftests/powerpc/tm/tm-tar.c new file mode 100644 index 000000000000..2d2fcc2b7a60 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-tar.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * Original: Michael Neuling 19/7/2013 | ||
5 | * Edited: Rashmica Gupta 01/12/2015 | ||
6 | * | ||
7 | * Do some transactions, see if the tar is corrupted. | ||
8 | * If the transaction is aborted, the TAR should be rolled back to the | ||
9 | * checkpointed value before the transaction began. The value written to | ||
10 | * TAR in suspended mode should only remain in TAR if the transaction | ||
11 | * completes. | ||
12 | */ | ||
13 | |||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <unistd.h> | ||
17 | #include <string.h> | ||
18 | |||
19 | #include "tm.h" | ||
20 | #include "utils.h" | ||
21 | |||
22 | int num_loops = 10000; | ||
23 | |||
24 | int test_tar(void) | ||
25 | { | ||
26 | int i; | ||
27 | |||
28 | SKIP_IF(!have_htm()); | ||
29 | |||
30 | for (i = 0; i < num_loops; i++) | ||
31 | { | ||
32 | uint64_t result = 0; | ||
33 | asm __volatile__( | ||
34 | "li 7, 1;" | ||
35 | "mtspr %[tar], 7;" /* tar = 1 */ | ||
36 | "tbegin.;" | ||
37 | "beq 3f;" | ||
38 | "li 4, 0x7000;" /* Loop lots, to use time */ | ||
39 | "2:;" /* Start loop */ | ||
40 | "li 7, 2;" | ||
41 | "mtspr %[tar], 7;" /* tar = 2 */ | ||
42 | "tsuspend.;" | ||
43 | "li 7, 3;" | ||
44 | "mtspr %[tar], 7;" /* tar = 3 */ | ||
45 | "tresume.;" | ||
46 | "subi 4, 4, 1;" | ||
47 | "cmpdi 4, 0;" | ||
48 | "bne 2b;" | ||
49 | "tend.;" | ||
50 | |||
51 | /* Transaction sucess! TAR should be 3 */ | ||
52 | "mfspr 7, %[tar];" | ||
53 | "ori %[res], 7, 4;" // res = 3|4 = 7 | ||
54 | "b 4f;" | ||
55 | |||
56 | /* Abort handler. TAR should be rolled back to 1 */ | ||
57 | "3:;" | ||
58 | "mfspr 7, %[tar];" | ||
59 | "ori %[res], 7, 8;" // res = 1|8 = 9 | ||
60 | "4:;" | ||
61 | |||
62 | : [res]"=r"(result) | ||
63 | : [tar]"i"(SPRN_TAR) | ||
64 | : "memory", "r0", "r4", "r7"); | ||
65 | |||
66 | /* If result is anything else other than 7 or 9, the tar | ||
67 | * value must have been corrupted. */ | ||
68 | if ((result != 7) && (result != 9)) | ||
69 | return 1; | ||
70 | } | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | int main(int argc, char *argv[]) | ||
75 | { | ||
76 | /* A low number of iterations (eg 100) can cause a false pass */ | ||
77 | if (argc > 1) { | ||
78 | if (strcmp(argv[1], "-h") == 0) { | ||
79 | printf("Syntax:\n\t%s [<num loops>]\n", | ||
80 | argv[0]); | ||
81 | return 1; | ||
82 | } else { | ||
83 | num_loops = atoi(argv[1]); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | printf("Starting, %d loops\n", num_loops); | ||
88 | |||
89 | return test_harness(test_tar, "tm_tar"); | ||
90 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-tmspr.c b/tools/testing/selftests/powerpc/tm/tm-tmspr.c new file mode 100644 index 000000000000..2bda81c7bf23 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-tmspr.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * Copyright 2015, Michael Neuling, IBM Corp. | ||
3 | * Licensed under GPLv2. | ||
4 | * | ||
5 | * Original: Michael Neuling 3/4/2014 | ||
6 | * Modified: Rashmica Gupta 8/12/2015 | ||
7 | * | ||
8 | * Check if any of the Transaction Memory SPRs get corrupted. | ||
9 | * - TFIAR - stores address of location of transaction failure | ||
10 | * - TFHAR - stores address of software failure handler (if transaction | ||
11 | * fails) | ||
12 | * - TEXASR - lots of info about the transacion(s) | ||
13 | * | ||
14 | * (1) create more threads than cpus | ||
15 | * (2) in each thread: | ||
16 | * (a) set TFIAR and TFHAR a unique value | ||
17 | * (b) loop for awhile, continually checking to see if | ||
18 | * either register has been corrupted. | ||
19 | * | ||
20 | * (3) Loop: | ||
21 | * (a) begin transaction | ||
22 | * (b) abort transaction | ||
23 | * (c) check TEXASR to see if FS has been corrupted | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #define _GNU_SOURCE | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <unistd.h> | ||
31 | #include <pthread.h> | ||
32 | #include <string.h> | ||
33 | |||
34 | #include "utils.h" | ||
35 | #include "tm.h" | ||
36 | |||
37 | int num_loops = 10000; | ||
38 | int passed = 1; | ||
39 | |||
40 | void tfiar_tfhar(void *in) | ||
41 | { | ||
42 | int i, cpu; | ||
43 | unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd; | ||
44 | cpu_set_t cpuset; | ||
45 | |||
46 | CPU_ZERO(&cpuset); | ||
47 | cpu = (unsigned long)in >> 1; | ||
48 | CPU_SET(cpu, &cpuset); | ||
49 | sched_setaffinity(0, sizeof(cpuset), &cpuset); | ||
50 | |||
51 | /* TFIAR: Last bit has to be high so userspace can read register */ | ||
52 | tfiar = ((unsigned long)in) + 1; | ||
53 | tfiar += 2; | ||
54 | mtspr(SPRN_TFIAR, tfiar); | ||
55 | |||
56 | /* TFHAR: Last two bits are reserved */ | ||
57 | tfhar = ((unsigned long)in); | ||
58 | tfhar &= ~0x3UL; | ||
59 | tfhar += 4; | ||
60 | mtspr(SPRN_TFHAR, tfhar); | ||
61 | |||
62 | for (i = 0; i < num_loops; i++) { | ||
63 | tfhar_rd = mfspr(SPRN_TFHAR); | ||
64 | tfiar_rd = mfspr(SPRN_TFIAR); | ||
65 | if ( (tfhar != tfhar_rd) || (tfiar != tfiar_rd) ) { | ||
66 | passed = 0; | ||
67 | return; | ||
68 | } | ||
69 | } | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | void texasr(void *in) | ||
74 | { | ||
75 | unsigned long i; | ||
76 | uint64_t result = 0; | ||
77 | |||
78 | for (i = 0; i < num_loops; i++) { | ||
79 | asm __volatile__( | ||
80 | "tbegin.;" | ||
81 | "beq 3f ;" | ||
82 | "tabort. 0 ;" | ||
83 | "tend.;" | ||
84 | |||
85 | /* Abort handler */ | ||
86 | "3: ;" | ||
87 | ::: "memory"); | ||
88 | |||
89 | /* Check the TEXASR */ | ||
90 | result = mfspr(SPRN_TEXASR); | ||
91 | if ((result & TEXASR_FS) == 0) { | ||
92 | passed = 0; | ||
93 | return; | ||
94 | } | ||
95 | } | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | int test_tmspr() | ||
100 | { | ||
101 | pthread_t thread; | ||
102 | int thread_num; | ||
103 | unsigned long i; | ||
104 | |||
105 | SKIP_IF(!have_htm()); | ||
106 | |||
107 | /* To cause some context switching */ | ||
108 | thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); | ||
109 | |||
110 | /* Test TFIAR and TFHAR */ | ||
111 | for (i = 0 ; i < thread_num ; i += 2){ | ||
112 | if (pthread_create(&thread, NULL, (void*)tfiar_tfhar, (void *)i)) | ||
113 | return EXIT_FAILURE; | ||
114 | } | ||
115 | if (pthread_join(thread, NULL) != 0) | ||
116 | return EXIT_FAILURE; | ||
117 | |||
118 | /* Test TEXASR */ | ||
119 | for (i = 0 ; i < thread_num ; i++){ | ||
120 | if (pthread_create(&thread, NULL, (void*)texasr, (void *)i)) | ||
121 | return EXIT_FAILURE; | ||
122 | } | ||
123 | if (pthread_join(thread, NULL) != 0) | ||
124 | return EXIT_FAILURE; | ||
125 | |||
126 | if (passed) | ||
127 | return 0; | ||
128 | else | ||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | int main(int argc, char *argv[]) | ||
133 | { | ||
134 | if (argc > 1) { | ||
135 | if (strcmp(argv[1], "-h") == 0) { | ||
136 | printf("Syntax:\t [<num loops>]\n"); | ||
137 | return 0; | ||
138 | } else { | ||
139 | num_loops = atoi(argv[1]); | ||
140 | } | ||
141 | } | ||
142 | return test_harness(test_tmspr, "tm_tmspr"); | ||
143 | } | ||
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index 175ac6ad10dd..a985cfaa535e 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h | |||
@@ -6,9 +6,12 @@ | |||
6 | #ifndef _SELFTESTS_POWERPC_UTILS_H | 6 | #ifndef _SELFTESTS_POWERPC_UTILS_H |
7 | #define _SELFTESTS_POWERPC_UTILS_H | 7 | #define _SELFTESTS_POWERPC_UTILS_H |
8 | 8 | ||
9 | #define __cacheline_aligned __attribute__((aligned(128))) | ||
10 | |||
9 | #include <stdint.h> | 11 | #include <stdint.h> |
10 | #include <stdbool.h> | 12 | #include <stdbool.h> |
11 | #include <linux/auxvec.h> | 13 | #include <linux/auxvec.h> |
14 | #include "reg.h" | ||
12 | 15 | ||
13 | /* Avoid headaches with PRI?64 - just use %ll? always */ | 16 | /* Avoid headaches with PRI?64 - just use %ll? always */ |
14 | typedef unsigned long long u64; | 17 | typedef unsigned long long u64; |
@@ -54,4 +57,9 @@ do { \ | |||
54 | #define _str(s) #s | 57 | #define _str(s) #s |
55 | #define str(s) _str(s) | 58 | #define str(s) _str(s) |
56 | 59 | ||
60 | /* POWER9 feature */ | ||
61 | #ifndef PPC_FEATURE2_ARCH_3_00 | ||
62 | #define PPC_FEATURE2_ARCH_3_00 0x00800000 | ||
63 | #endif | ||
64 | |||
57 | #endif /* _SELFTESTS_POWERPC_UTILS_H */ | 65 | #endif /* _SELFTESTS_POWERPC_UTILS_H */ |
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 150829dd7998..2e58549b2f02 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Test code for seccomp bpf. | 5 | * Test code for seccomp bpf. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <sys/types.h> | ||
8 | #include <asm/siginfo.h> | 9 | #include <asm/siginfo.h> |
9 | #define __have_siginfo_t 1 | 10 | #define __have_siginfo_t 1 |
10 | #define __have_sigval_t 1 | 11 | #define __have_sigval_t 1 |
@@ -14,7 +15,6 @@ | |||
14 | #include <linux/filter.h> | 15 | #include <linux/filter.h> |
15 | #include <sys/prctl.h> | 16 | #include <sys/prctl.h> |
16 | #include <sys/ptrace.h> | 17 | #include <sys/ptrace.h> |
17 | #include <sys/types.h> | ||
18 | #include <sys/user.h> | 18 | #include <sys/user.h> |
19 | #include <linux/prctl.h> | 19 | #include <linux/prctl.h> |
20 | #include <linux/ptrace.h> | 20 | #include <linux/ptrace.h> |
@@ -1234,6 +1234,10 @@ TEST_F(TRACE_poke, getpid_runs_normally) | |||
1234 | # define ARCH_REGS struct user_pt_regs | 1234 | # define ARCH_REGS struct user_pt_regs |
1235 | # define SYSCALL_NUM regs[8] | 1235 | # define SYSCALL_NUM regs[8] |
1236 | # define SYSCALL_RET regs[0] | 1236 | # define SYSCALL_RET regs[0] |
1237 | #elif defined(__hppa__) | ||
1238 | # define ARCH_REGS struct user_regs_struct | ||
1239 | # define SYSCALL_NUM gr[20] | ||
1240 | # define SYSCALL_RET gr[28] | ||
1237 | #elif defined(__powerpc__) | 1241 | #elif defined(__powerpc__) |
1238 | # define ARCH_REGS struct pt_regs | 1242 | # define ARCH_REGS struct pt_regs |
1239 | # define SYSCALL_NUM gpr[0] | 1243 | # define SYSCALL_NUM gpr[0] |
@@ -1242,6 +1246,12 @@ TEST_F(TRACE_poke, getpid_runs_normally) | |||
1242 | # define ARCH_REGS s390_regs | 1246 | # define ARCH_REGS s390_regs |
1243 | # define SYSCALL_NUM gprs[2] | 1247 | # define SYSCALL_NUM gprs[2] |
1244 | # define SYSCALL_RET gprs[2] | 1248 | # define SYSCALL_RET gprs[2] |
1249 | #elif defined(__mips__) | ||
1250 | # define ARCH_REGS struct pt_regs | ||
1251 | # define SYSCALL_NUM regs[2] | ||
1252 | # define SYSCALL_SYSCALL_NUM regs[4] | ||
1253 | # define SYSCALL_RET regs[2] | ||
1254 | # define SYSCALL_NUM_RET_SHARE_REG | ||
1245 | #else | 1255 | #else |
1246 | # error "Do not know how to find your architecture's registers and syscalls" | 1256 | # error "Do not know how to find your architecture's registers and syscalls" |
1247 | #endif | 1257 | #endif |
@@ -1249,7 +1259,7 @@ TEST_F(TRACE_poke, getpid_runs_normally) | |||
1249 | /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for | 1259 | /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for |
1250 | * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). | 1260 | * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). |
1251 | */ | 1261 | */ |
1252 | #if defined(__x86_64__) || defined(__i386__) | 1262 | #if defined(__x86_64__) || defined(__i386__) || defined(__mips__) |
1253 | #define HAVE_GETREGS | 1263 | #define HAVE_GETREGS |
1254 | #endif | 1264 | #endif |
1255 | 1265 | ||
@@ -1273,6 +1283,10 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee) | |||
1273 | } | 1283 | } |
1274 | #endif | 1284 | #endif |
1275 | 1285 | ||
1286 | #if defined(__mips__) | ||
1287 | if (regs.SYSCALL_NUM == __NR_O32_Linux) | ||
1288 | return regs.SYSCALL_SYSCALL_NUM; | ||
1289 | #endif | ||
1276 | return regs.SYSCALL_NUM; | 1290 | return regs.SYSCALL_NUM; |
1277 | } | 1291 | } |
1278 | 1292 | ||
@@ -1293,10 +1307,17 @@ void change_syscall(struct __test_metadata *_metadata, | |||
1293 | EXPECT_EQ(0, ret); | 1307 | EXPECT_EQ(0, ret); |
1294 | 1308 | ||
1295 | #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ | 1309 | #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ |
1296 | defined(__s390__) | 1310 | defined(__s390__) || defined(__hppa__) |
1297 | { | 1311 | { |
1298 | regs.SYSCALL_NUM = syscall; | 1312 | regs.SYSCALL_NUM = syscall; |
1299 | } | 1313 | } |
1314 | #elif defined(__mips__) | ||
1315 | { | ||
1316 | if (regs.SYSCALL_NUM == __NR_O32_Linux) | ||
1317 | regs.SYSCALL_SYSCALL_NUM = syscall; | ||
1318 | else | ||
1319 | regs.SYSCALL_NUM = syscall; | ||
1320 | } | ||
1300 | 1321 | ||
1301 | #elif defined(__arm__) | 1322 | #elif defined(__arm__) |
1302 | # ifndef PTRACE_SET_SYSCALL | 1323 | # ifndef PTRACE_SET_SYSCALL |
@@ -1327,7 +1348,11 @@ void change_syscall(struct __test_metadata *_metadata, | |||
1327 | 1348 | ||
1328 | /* If syscall is skipped, change return value. */ | 1349 | /* If syscall is skipped, change return value. */ |
1329 | if (syscall == -1) | 1350 | if (syscall == -1) |
1351 | #ifdef SYSCALL_NUM_RET_SHARE_REG | ||
1352 | TH_LOG("Can't modify syscall return on this architecture"); | ||
1353 | #else | ||
1330 | regs.SYSCALL_RET = 1; | 1354 | regs.SYSCALL_RET = 1; |
1355 | #endif | ||
1331 | 1356 | ||
1332 | #ifdef HAVE_GETREGS | 1357 | #ifdef HAVE_GETREGS |
1333 | ret = ptrace(PTRACE_SETREGS, tracee, 0, ®s); | 1358 | ret = ptrace(PTRACE_SETREGS, tracee, 0, ®s); |
@@ -1465,8 +1490,13 @@ TEST_F(TRACE_syscall, syscall_dropped) | |||
1465 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); | 1490 | ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); |
1466 | ASSERT_EQ(0, ret); | 1491 | ASSERT_EQ(0, ret); |
1467 | 1492 | ||
1493 | #ifdef SYSCALL_NUM_RET_SHARE_REG | ||
1494 | /* gettid has been skipped */ | ||
1495 | EXPECT_EQ(-1, syscall(__NR_gettid)); | ||
1496 | #else | ||
1468 | /* gettid has been skipped and an altered return value stored. */ | 1497 | /* gettid has been skipped and an altered return value stored. */ |
1469 | EXPECT_EQ(1, syscall(__NR_gettid)); | 1498 | EXPECT_EQ(1, syscall(__NR_gettid)); |
1499 | #endif | ||
1470 | EXPECT_NE(self->mytid, syscall(__NR_gettid)); | 1500 | EXPECT_NE(self->mytid, syscall(__NR_gettid)); |
1471 | } | 1501 | } |
1472 | 1502 | ||
@@ -1479,6 +1509,8 @@ TEST_F(TRACE_syscall, syscall_dropped) | |||
1479 | # define __NR_seccomp 383 | 1509 | # define __NR_seccomp 383 |
1480 | # elif defined(__aarch64__) | 1510 | # elif defined(__aarch64__) |
1481 | # define __NR_seccomp 277 | 1511 | # define __NR_seccomp 277 |
1512 | # elif defined(__hppa__) | ||
1513 | # define __NR_seccomp 338 | ||
1482 | # elif defined(__powerpc__) | 1514 | # elif defined(__powerpc__) |
1483 | # define __NR_seccomp 358 | 1515 | # define __NR_seccomp 358 |
1484 | # elif defined(__s390__) | 1516 | # elif defined(__s390__) |
diff --git a/tools/testing/selftests/vm/thuge-gen.c b/tools/testing/selftests/vm/thuge-gen.c index c87957295f74..0bc737a75150 100644 --- a/tools/testing/selftests/vm/thuge-gen.c +++ b/tools/testing/selftests/vm/thuge-gen.c | |||
@@ -30,7 +30,9 @@ | |||
30 | #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) | 30 | #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) |
31 | #define MAP_HUGE_SHIFT 26 | 31 | #define MAP_HUGE_SHIFT 26 |
32 | #define MAP_HUGE_MASK 0x3f | 32 | #define MAP_HUGE_MASK 0x3f |
33 | #if !defined(MAP_HUGETLB) | ||
33 | #define MAP_HUGETLB 0x40000 | 34 | #define MAP_HUGETLB 0x40000 |
35 | #endif | ||
34 | 36 | ||
35 | #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ | 37 | #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ |
36 | #define SHM_HUGE_SHIFT 26 | 38 | #define SHM_HUGE_SHIFT 26 |
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am index 7c8f8a4d54e4..90daf95c0804 100644 --- a/tools/usb/usbip/libsrc/Makefile.am +++ b/tools/usb/usbip/libsrc/Makefile.am | |||
@@ -4,5 +4,7 @@ libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ | |||
4 | 4 | ||
5 | lib_LTLIBRARIES := libusbip.la | 5 | lib_LTLIBRARIES := libusbip.la |
6 | libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ | 6 | libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ |
7 | usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ | 7 | usbip_device_driver.c usbip_device_driver.h \ |
8 | usbip_common.c usbip_common.h usbip_host_common.h \ | ||
9 | usbip_host_common.c vhci_driver.c vhci_driver.h \ | ||
8 | sysfs_utils.c sysfs_utils.h | 10 | sysfs_utils.c sysfs_utils.h |
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h index 15fe792e1e96..51ef5fe485dd 100644 --- a/tools/usb/usbip/libsrc/usbip_common.h +++ b/tools/usb/usbip/libsrc/usbip_common.h | |||
@@ -25,9 +25,12 @@ | |||
25 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" | 25 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #define VUDC_DEVICE_DESCR_FILE "dev_desc" | ||
29 | |||
28 | /* kernel module names */ | 30 | /* kernel module names */ |
29 | #define USBIP_CORE_MOD_NAME "usbip-core" | 31 | #define USBIP_CORE_MOD_NAME "usbip-core" |
30 | #define USBIP_HOST_DRV_NAME "usbip-host" | 32 | #define USBIP_HOST_DRV_NAME "usbip-host" |
33 | #define USBIP_DEVICE_DRV_NAME "usbip-vudc" | ||
31 | #define USBIP_VHCI_DRV_NAME "vhci_hcd" | 34 | #define USBIP_VHCI_DRV_NAME "vhci_hcd" |
32 | 35 | ||
33 | /* sysfs constants */ | 36 | /* sysfs constants */ |
diff --git a/tools/usb/usbip/libsrc/usbip_device_driver.c b/tools/usb/usbip/libsrc/usbip_device_driver.c new file mode 100644 index 000000000000..e059b7d1ec5b --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_device_driver.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> | ||
3 | * 2015 Samsung Electronics | ||
4 | * Author: Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
5 | * | ||
6 | * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is: | ||
7 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
8 | * 2005-2007 Takahiro Hirofuchi | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | */ | ||
23 | |||
24 | #include <fcntl.h> | ||
25 | #include <string.h> | ||
26 | #include <linux/usb/ch9.h> | ||
27 | |||
28 | #include <unistd.h> | ||
29 | |||
30 | #include "usbip_host_common.h" | ||
31 | #include "usbip_device_driver.h" | ||
32 | |||
33 | #undef PROGNAME | ||
34 | #define PROGNAME "libusbip" | ||
35 | |||
36 | #define copy_descr_attr16(dev, descr, attr) \ | ||
37 | ((dev)->attr = le16toh((descr)->attr)) \ | ||
38 | |||
39 | #define copy_descr_attr(dev, descr, attr) \ | ||
40 | ((dev)->attr = (descr)->attr) \ | ||
41 | |||
42 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
43 | |||
44 | static struct { | ||
45 | enum usb_device_speed speed; | ||
46 | const char *name; | ||
47 | } speed_names[] = { | ||
48 | { | ||
49 | .speed = USB_SPEED_UNKNOWN, | ||
50 | .name = "UNKNOWN", | ||
51 | }, | ||
52 | { | ||
53 | .speed = USB_SPEED_LOW, | ||
54 | .name = "low-speed", | ||
55 | }, | ||
56 | { | ||
57 | .speed = USB_SPEED_FULL, | ||
58 | .name = "full-speed", | ||
59 | }, | ||
60 | { | ||
61 | .speed = USB_SPEED_HIGH, | ||
62 | .name = "high-speed", | ||
63 | }, | ||
64 | { | ||
65 | .speed = USB_SPEED_WIRELESS, | ||
66 | .name = "wireless", | ||
67 | }, | ||
68 | { | ||
69 | .speed = USB_SPEED_SUPER, | ||
70 | .name = "super-speed", | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | static | ||
75 | int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev) | ||
76 | { | ||
77 | const char *path, *name; | ||
78 | char filepath[SYSFS_PATH_MAX]; | ||
79 | struct usb_device_descriptor descr; | ||
80 | unsigned i; | ||
81 | FILE *fd = NULL; | ||
82 | struct udev_device *plat; | ||
83 | const char *speed; | ||
84 | int ret = 0; | ||
85 | |||
86 | plat = udev_device_get_parent(sdev); | ||
87 | path = udev_device_get_syspath(plat); | ||
88 | snprintf(filepath, SYSFS_PATH_MAX, "%s/%s", | ||
89 | path, VUDC_DEVICE_DESCR_FILE); | ||
90 | fd = fopen(filepath, "r"); | ||
91 | if (!fd) | ||
92 | return -1; | ||
93 | ret = fread((char *) &descr, sizeof(descr), 1, fd); | ||
94 | if (ret < 0) | ||
95 | return -1; | ||
96 | fclose(fd); | ||
97 | |||
98 | copy_descr_attr(dev, &descr, bDeviceClass); | ||
99 | copy_descr_attr(dev, &descr, bDeviceSubClass); | ||
100 | copy_descr_attr(dev, &descr, bDeviceProtocol); | ||
101 | copy_descr_attr(dev, &descr, bNumConfigurations); | ||
102 | copy_descr_attr16(dev, &descr, idVendor); | ||
103 | copy_descr_attr16(dev, &descr, idProduct); | ||
104 | copy_descr_attr16(dev, &descr, bcdDevice); | ||
105 | |||
106 | strncpy(dev->path, path, SYSFS_PATH_MAX); | ||
107 | |||
108 | dev->speed = USB_SPEED_UNKNOWN; | ||
109 | speed = udev_device_get_sysattr_value(sdev, "current_speed"); | ||
110 | if (speed) { | ||
111 | for (i = 0; i < ARRAY_SIZE(speed_names); i++) { | ||
112 | if (!strcmp(speed_names[i].name, speed)) { | ||
113 | dev->speed = speed_names[i].speed; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* Only used for user output, little sense to output them in general */ | ||
120 | dev->bNumInterfaces = 0; | ||
121 | dev->bConfigurationValue = 0; | ||
122 | dev->busnum = 0; | ||
123 | |||
124 | name = udev_device_get_sysname(plat); | ||
125 | strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int is_my_device(struct udev_device *dev) | ||
130 | { | ||
131 | const char *driver; | ||
132 | |||
133 | driver = udev_device_get_property_value(dev, "USB_UDC_NAME"); | ||
134 | return driver != NULL && !strcmp(driver, USBIP_DEVICE_DRV_NAME); | ||
135 | } | ||
136 | |||
137 | static int usbip_device_driver_open(struct usbip_host_driver *hdriver) | ||
138 | { | ||
139 | int ret; | ||
140 | |||
141 | hdriver->ndevs = 0; | ||
142 | INIT_LIST_HEAD(&hdriver->edev_list); | ||
143 | |||
144 | ret = usbip_generic_driver_open(hdriver); | ||
145 | if (ret) | ||
146 | err("please load " USBIP_CORE_MOD_NAME ".ko and " | ||
147 | USBIP_DEVICE_DRV_NAME ".ko!"); | ||
148 | |||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | struct usbip_host_driver device_driver = { | ||
153 | .edev_list = LIST_HEAD_INIT(device_driver.edev_list), | ||
154 | .udev_subsystem = "udc", | ||
155 | .ops = { | ||
156 | .open = usbip_device_driver_open, | ||
157 | .close = usbip_generic_driver_close, | ||
158 | .refresh_device_list = usbip_generic_refresh_device_list, | ||
159 | .get_device = usbip_generic_get_device, | ||
160 | .read_device = read_usb_vudc_device, | ||
161 | .is_my_device = is_my_device, | ||
162 | }, | ||
163 | }; | ||
diff --git a/tools/usb/usbip/libsrc/usbip_device_driver.h b/tools/usb/usbip/libsrc/usbip_device_driver.h new file mode 100644 index 000000000000..54cb658b37a3 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_device_driver.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> | ||
3 | * 2015 Samsung Electronics | ||
4 | * Author: Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
5 | * | ||
6 | * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is: | ||
7 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
8 | * 2005-2007 Takahiro Hirofuchi | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | */ | ||
23 | |||
24 | #ifndef __USBIP_DEVICE_DRIVER_H | ||
25 | #define __USBIP_DEVICE_DRIVER_H | ||
26 | |||
27 | #include <stdint.h> | ||
28 | #include "usbip_common.h" | ||
29 | #include "usbip_host_common.h" | ||
30 | #include "list.h" | ||
31 | |||
32 | extern struct usbip_host_driver device_driver; | ||
33 | |||
34 | #endif /* __USBIP_DEVICE_DRIVER_H */ | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c new file mode 100644 index 000000000000..9d415228883d --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_common.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2016 Samsung Electronics | ||
3 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
4 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
5 | * | ||
6 | * Refactored from usbip_host_driver.c, which is: | ||
7 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
8 | * 2005-2007 Takahiro Hirofuchi | ||
9 | * | ||
10 | * This program is free software: you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | */ | ||
23 | |||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | |||
28 | #include <errno.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | #include <libudev.h> | ||
32 | |||
33 | #include "usbip_common.h" | ||
34 | #include "usbip_host_common.h" | ||
35 | #include "list.h" | ||
36 | #include "sysfs_utils.h" | ||
37 | |||
38 | struct udev *udev_context; | ||
39 | |||
40 | static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | ||
41 | { | ||
42 | char status_attr_path[SYSFS_PATH_MAX]; | ||
43 | int fd; | ||
44 | int length; | ||
45 | char status; | ||
46 | int value = 0; | ||
47 | |||
48 | snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", | ||
49 | udev->path); | ||
50 | |||
51 | fd = open(status_attr_path, O_RDONLY); | ||
52 | if (fd < 0) { | ||
53 | err("error opening attribute %s", status_attr_path); | ||
54 | return -1; | ||
55 | } | ||
56 | |||
57 | length = read(fd, &status, 1); | ||
58 | if (length < 0) { | ||
59 | err("error reading attribute %s", status_attr_path); | ||
60 | close(fd); | ||
61 | return -1; | ||
62 | } | ||
63 | |||
64 | value = atoi(&status); | ||
65 | |||
66 | return value; | ||
67 | } | ||
68 | |||
69 | static | ||
70 | struct usbip_exported_device *usbip_exported_device_new( | ||
71 | struct usbip_host_driver *hdriver, const char *sdevpath) | ||
72 | { | ||
73 | struct usbip_exported_device *edev = NULL; | ||
74 | struct usbip_exported_device *edev_old; | ||
75 | size_t size; | ||
76 | int i; | ||
77 | |||
78 | edev = calloc(1, sizeof(struct usbip_exported_device)); | ||
79 | |||
80 | edev->sudev = | ||
81 | udev_device_new_from_syspath(udev_context, sdevpath); | ||
82 | if (!edev->sudev) { | ||
83 | err("udev_device_new_from_syspath: %s", sdevpath); | ||
84 | goto err; | ||
85 | } | ||
86 | |||
87 | if (hdriver->ops.read_device(edev->sudev, &edev->udev) < 0) | ||
88 | goto err; | ||
89 | |||
90 | edev->status = read_attr_usbip_status(&edev->udev); | ||
91 | if (edev->status < 0) | ||
92 | goto err; | ||
93 | |||
94 | /* reallocate buffer to include usb interface data */ | ||
95 | size = sizeof(struct usbip_exported_device) + | ||
96 | edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); | ||
97 | |||
98 | edev_old = edev; | ||
99 | edev = realloc(edev, size); | ||
100 | if (!edev) { | ||
101 | edev = edev_old; | ||
102 | dbg("realloc failed"); | ||
103 | goto err; | ||
104 | } | ||
105 | |||
106 | for (i = 0; i < edev->udev.bNumInterfaces; i++) { | ||
107 | /* vudc does not support reading interfaces */ | ||
108 | if (!hdriver->ops.read_interface) | ||
109 | break; | ||
110 | hdriver->ops.read_interface(&edev->udev, i, &edev->uinf[i]); | ||
111 | } | ||
112 | |||
113 | return edev; | ||
114 | err: | ||
115 | if (edev->sudev) | ||
116 | udev_device_unref(edev->sudev); | ||
117 | if (edev) | ||
118 | free(edev); | ||
119 | |||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | static int refresh_exported_devices(struct usbip_host_driver *hdriver) | ||
124 | { | ||
125 | struct usbip_exported_device *edev; | ||
126 | struct udev_enumerate *enumerate; | ||
127 | struct udev_list_entry *devices, *dev_list_entry; | ||
128 | struct udev_device *dev; | ||
129 | const char *path; | ||
130 | |||
131 | enumerate = udev_enumerate_new(udev_context); | ||
132 | udev_enumerate_add_match_subsystem(enumerate, hdriver->udev_subsystem); | ||
133 | udev_enumerate_scan_devices(enumerate); | ||
134 | |||
135 | devices = udev_enumerate_get_list_entry(enumerate); | ||
136 | |||
137 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
138 | path = udev_list_entry_get_name(dev_list_entry); | ||
139 | dev = udev_device_new_from_syspath(udev_context, | ||
140 | path); | ||
141 | if (dev == NULL) | ||
142 | continue; | ||
143 | |||
144 | /* Check whether device uses usbip driver. */ | ||
145 | if (hdriver->ops.is_my_device(dev)) { | ||
146 | edev = usbip_exported_device_new(hdriver, path); | ||
147 | if (!edev) { | ||
148 | dbg("usbip_exported_device_new failed"); | ||
149 | continue; | ||
150 | } | ||
151 | |||
152 | list_add(&edev->node, &hdriver->edev_list); | ||
153 | hdriver->ndevs++; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void usbip_exported_device_destroy(struct list_head *devs) | ||
161 | { | ||
162 | struct list_head *i, *tmp; | ||
163 | struct usbip_exported_device *edev; | ||
164 | |||
165 | list_for_each_safe(i, tmp, devs) { | ||
166 | edev = list_entry(i, struct usbip_exported_device, node); | ||
167 | list_del(i); | ||
168 | free(edev); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | int usbip_generic_driver_open(struct usbip_host_driver *hdriver) | ||
173 | { | ||
174 | int rc; | ||
175 | |||
176 | udev_context = udev_new(); | ||
177 | if (!udev_context) { | ||
178 | err("udev_new failed"); | ||
179 | return -1; | ||
180 | } | ||
181 | |||
182 | rc = refresh_exported_devices(hdriver); | ||
183 | if (rc < 0) | ||
184 | goto err; | ||
185 | return 0; | ||
186 | err: | ||
187 | udev_unref(udev_context); | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | void usbip_generic_driver_close(struct usbip_host_driver *hdriver) | ||
192 | { | ||
193 | if (!hdriver) | ||
194 | return; | ||
195 | |||
196 | usbip_exported_device_destroy(&hdriver->edev_list); | ||
197 | |||
198 | udev_unref(udev_context); | ||
199 | } | ||
200 | |||
201 | int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver) | ||
202 | { | ||
203 | int rc; | ||
204 | |||
205 | usbip_exported_device_destroy(&hdriver->edev_list); | ||
206 | |||
207 | hdriver->ndevs = 0; | ||
208 | INIT_LIST_HEAD(&hdriver->edev_list); | ||
209 | |||
210 | rc = refresh_exported_devices(hdriver); | ||
211 | if (rc < 0) | ||
212 | return -1; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | int usbip_export_device(struct usbip_exported_device *edev, int sockfd) | ||
218 | { | ||
219 | char attr_name[] = "usbip_sockfd"; | ||
220 | char sockfd_attr_path[SYSFS_PATH_MAX]; | ||
221 | char sockfd_buff[30]; | ||
222 | int ret; | ||
223 | |||
224 | if (edev->status != SDEV_ST_AVAILABLE) { | ||
225 | dbg("device not available: %s", edev->udev.busid); | ||
226 | switch (edev->status) { | ||
227 | case SDEV_ST_ERROR: | ||
228 | dbg("status SDEV_ST_ERROR"); | ||
229 | break; | ||
230 | case SDEV_ST_USED: | ||
231 | dbg("status SDEV_ST_USED"); | ||
232 | break; | ||
233 | default: | ||
234 | dbg("status unknown: 0x%x", edev->status); | ||
235 | } | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | /* only the first interface is true */ | ||
240 | snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", | ||
241 | edev->udev.path, attr_name); | ||
242 | |||
243 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); | ||
244 | |||
245 | ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, | ||
246 | strlen(sockfd_buff)); | ||
247 | if (ret < 0) { | ||
248 | err("write_sysfs_attribute failed: sockfd %s to %s", | ||
249 | sockfd_buff, sockfd_attr_path); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | info("connect: %s", edev->udev.busid); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | struct usbip_exported_device *usbip_generic_get_device( | ||
259 | struct usbip_host_driver *hdriver, int num) | ||
260 | { | ||
261 | struct list_head *i; | ||
262 | struct usbip_exported_device *edev; | ||
263 | int cnt = 0; | ||
264 | |||
265 | list_for_each(i, &hdriver->edev_list) { | ||
266 | edev = list_entry(i, struct usbip_exported_device, node); | ||
267 | if (num == cnt) | ||
268 | return edev; | ||
269 | cnt++; | ||
270 | } | ||
271 | |||
272 | return NULL; | ||
273 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.h b/tools/usb/usbip/libsrc/usbip_host_common.h new file mode 100644 index 000000000000..a64b8033fe64 --- /dev/null +++ b/tools/usb/usbip/libsrc/usbip_host_common.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2016 Samsung Electronics | ||
3 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
4 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
5 | * | ||
6 | * Refactored from usbip_host_driver.c, which is: | ||
7 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | ||
8 | * 2005-2007 Takahiro Hirofuchi | ||
9 | * | ||
10 | * This program is free software: you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | */ | ||
23 | |||
24 | #ifndef __USBIP_HOST_COMMON_H | ||
25 | #define __USBIP_HOST_COMMON_H | ||
26 | |||
27 | #include <stdint.h> | ||
28 | #include <libudev.h> | ||
29 | #include <errno.h> | ||
30 | #include "list.h" | ||
31 | #include "usbip_common.h" | ||
32 | #include "sysfs_utils.h" | ||
33 | |||
34 | struct usbip_host_driver; | ||
35 | |||
36 | struct usbip_host_driver_ops { | ||
37 | int (*open)(struct usbip_host_driver *hdriver); | ||
38 | void (*close)(struct usbip_host_driver *hdriver); | ||
39 | int (*refresh_device_list)(struct usbip_host_driver *hdriver); | ||
40 | struct usbip_exported_device * (*get_device)( | ||
41 | struct usbip_host_driver *hdriver, int num); | ||
42 | |||
43 | int (*read_device)(struct udev_device *sdev, | ||
44 | struct usbip_usb_device *dev); | ||
45 | int (*read_interface)(struct usbip_usb_device *udev, int i, | ||
46 | struct usbip_usb_interface *uinf); | ||
47 | int (*is_my_device)(struct udev_device *udev); | ||
48 | }; | ||
49 | |||
50 | struct usbip_host_driver { | ||
51 | int ndevs; | ||
52 | /* list of exported device */ | ||
53 | struct list_head edev_list; | ||
54 | const char *udev_subsystem; | ||
55 | struct usbip_host_driver_ops ops; | ||
56 | }; | ||
57 | |||
58 | struct usbip_exported_device { | ||
59 | struct udev_device *sudev; | ||
60 | int32_t status; | ||
61 | struct usbip_usb_device udev; | ||
62 | struct list_head node; | ||
63 | struct usbip_usb_interface uinf[]; | ||
64 | }; | ||
65 | |||
66 | /* External API to access the driver */ | ||
67 | static inline int usbip_driver_open(struct usbip_host_driver *hdriver) | ||
68 | { | ||
69 | if (!hdriver->ops.open) | ||
70 | return -EOPNOTSUPP; | ||
71 | return hdriver->ops.open(hdriver); | ||
72 | } | ||
73 | |||
74 | static inline void usbip_driver_close(struct usbip_host_driver *hdriver) | ||
75 | { | ||
76 | if (!hdriver->ops.close) | ||
77 | return; | ||
78 | hdriver->ops.close(hdriver); | ||
79 | } | ||
80 | |||
81 | static inline int usbip_refresh_device_list(struct usbip_host_driver *hdriver) | ||
82 | { | ||
83 | if (!hdriver->ops.refresh_device_list) | ||
84 | return -EOPNOTSUPP; | ||
85 | return hdriver->ops.refresh_device_list(hdriver); | ||
86 | } | ||
87 | |||
88 | static inline struct usbip_exported_device * | ||
89 | usbip_get_device(struct usbip_host_driver *hdriver, int num) | ||
90 | { | ||
91 | if (!hdriver->ops.get_device) | ||
92 | return NULL; | ||
93 | return hdriver->ops.get_device(hdriver, num); | ||
94 | } | ||
95 | |||
96 | /* Helper functions for implementing driver backend */ | ||
97 | int usbip_generic_driver_open(struct usbip_host_driver *hdriver); | ||
98 | void usbip_generic_driver_close(struct usbip_host_driver *hdriver); | ||
99 | int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver); | ||
100 | int usbip_export_device(struct usbip_exported_device *edev, int sockfd); | ||
101 | struct usbip_exported_device *usbip_generic_get_device( | ||
102 | struct usbip_host_driver *hdriver, int num); | ||
103 | |||
104 | #endif /* __USBIP_HOST_COMMON_H */ | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c index bef08d5c44e8..4de6edc54d35 100644 --- a/tools/usb/usbip/libsrc/usbip_host_driver.c +++ b/tools/usb/usbip/libsrc/usbip_host_driver.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> |
3 | * 2005-2007 Takahiro Hirofuchi | 3 | * 2005-2007 Takahiro Hirofuchi |
4 | * Copyright (C) 2015-2016 Samsung Electronics | ||
5 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
6 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
4 | * | 7 | * |
5 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -16,265 +19,47 @@ | |||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 20 | */ |
18 | 21 | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <fcntl.h> | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <unistd.h> | 22 | #include <unistd.h> |
25 | |||
26 | #include <libudev.h> | 23 | #include <libudev.h> |
27 | 24 | ||
28 | #include "usbip_common.h" | 25 | #include "usbip_host_common.h" |
29 | #include "usbip_host_driver.h" | 26 | #include "usbip_host_driver.h" |
30 | #include "list.h" | ||
31 | #include "sysfs_utils.h" | ||
32 | 27 | ||
33 | #undef PROGNAME | 28 | #undef PROGNAME |
34 | #define PROGNAME "libusbip" | 29 | #define PROGNAME "libusbip" |
35 | 30 | ||
36 | struct usbip_host_driver *host_driver; | 31 | static int is_my_device(struct udev_device *dev) |
37 | struct udev *udev_context; | ||
38 | |||
39 | static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) | ||
40 | { | ||
41 | char status_attr_path[SYSFS_PATH_MAX]; | ||
42 | int fd; | ||
43 | int length; | ||
44 | char status; | ||
45 | int value = 0; | ||
46 | |||
47 | snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", | ||
48 | udev->path); | ||
49 | |||
50 | fd = open(status_attr_path, O_RDONLY); | ||
51 | if (fd < 0) { | ||
52 | err("error opening attribute %s", status_attr_path); | ||
53 | return -1; | ||
54 | } | ||
55 | |||
56 | length = read(fd, &status, 1); | ||
57 | if (length < 0) { | ||
58 | err("error reading attribute %s", status_attr_path); | ||
59 | close(fd); | ||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | value = atoi(&status); | ||
64 | |||
65 | return value; | ||
66 | } | ||
67 | |||
68 | static | ||
69 | struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath) | ||
70 | { | ||
71 | struct usbip_exported_device *edev = NULL; | ||
72 | struct usbip_exported_device *edev_old; | ||
73 | size_t size; | ||
74 | int i; | ||
75 | |||
76 | edev = calloc(1, sizeof(struct usbip_exported_device)); | ||
77 | |||
78 | edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath); | ||
79 | if (!edev->sudev) { | ||
80 | err("udev_device_new_from_syspath: %s", sdevpath); | ||
81 | goto err; | ||
82 | } | ||
83 | |||
84 | read_usb_device(edev->sudev, &edev->udev); | ||
85 | |||
86 | edev->status = read_attr_usbip_status(&edev->udev); | ||
87 | if (edev->status < 0) | ||
88 | goto err; | ||
89 | |||
90 | /* reallocate buffer to include usb interface data */ | ||
91 | size = sizeof(struct usbip_exported_device) + | ||
92 | edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); | ||
93 | |||
94 | edev_old = edev; | ||
95 | edev = realloc(edev, size); | ||
96 | if (!edev) { | ||
97 | edev = edev_old; | ||
98 | dbg("realloc failed"); | ||
99 | goto err; | ||
100 | } | ||
101 | |||
102 | for (i = 0; i < edev->udev.bNumInterfaces; i++) | ||
103 | read_usb_interface(&edev->udev, i, &edev->uinf[i]); | ||
104 | |||
105 | return edev; | ||
106 | err: | ||
107 | if (edev->sudev) | ||
108 | udev_device_unref(edev->sudev); | ||
109 | if (edev) | ||
110 | free(edev); | ||
111 | |||
112 | return NULL; | ||
113 | } | ||
114 | |||
115 | static int refresh_exported_devices(void) | ||
116 | { | 32 | { |
117 | struct usbip_exported_device *edev; | ||
118 | struct udev_enumerate *enumerate; | ||
119 | struct udev_list_entry *devices, *dev_list_entry; | ||
120 | struct udev_device *dev; | ||
121 | const char *path; | ||
122 | const char *driver; | 33 | const char *driver; |
123 | 34 | ||
124 | enumerate = udev_enumerate_new(udev_context); | 35 | driver = udev_device_get_driver(dev); |
125 | udev_enumerate_add_match_subsystem(enumerate, "usb"); | 36 | return driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME); |
126 | udev_enumerate_scan_devices(enumerate); | ||
127 | |||
128 | devices = udev_enumerate_get_list_entry(enumerate); | ||
129 | |||
130 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
131 | path = udev_list_entry_get_name(dev_list_entry); | ||
132 | dev = udev_device_new_from_syspath(udev_context, path); | ||
133 | if (dev == NULL) | ||
134 | continue; | ||
135 | |||
136 | /* Check whether device uses usbip-host driver. */ | ||
137 | driver = udev_device_get_driver(dev); | ||
138 | if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { | ||
139 | edev = usbip_exported_device_new(path); | ||
140 | if (!edev) { | ||
141 | dbg("usbip_exported_device_new failed"); | ||
142 | continue; | ||
143 | } | ||
144 | |||
145 | list_add(&edev->node, &host_driver->edev_list); | ||
146 | host_driver->ndevs++; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void usbip_exported_device_destroy(void) | ||
154 | { | ||
155 | struct list_head *i, *tmp; | ||
156 | struct usbip_exported_device *edev; | ||
157 | |||
158 | list_for_each_safe(i, tmp, &host_driver->edev_list) { | ||
159 | edev = list_entry(i, struct usbip_exported_device, node); | ||
160 | list_del(i); | ||
161 | free(edev); | ||
162 | } | ||
163 | } | 37 | } |
164 | 38 | ||
165 | int usbip_host_driver_open(void) | 39 | static int usbip_host_driver_open(struct usbip_host_driver *hdriver) |
166 | { | 40 | { |
167 | int rc; | ||
168 | |||
169 | udev_context = udev_new(); | ||
170 | if (!udev_context) { | ||
171 | err("udev_new failed"); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | host_driver = calloc(1, sizeof(*host_driver)); | ||
176 | |||
177 | host_driver->ndevs = 0; | ||
178 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
179 | |||
180 | rc = refresh_exported_devices(); | ||
181 | if (rc < 0) | ||
182 | goto err_free_host_driver; | ||
183 | |||
184 | return 0; | ||
185 | |||
186 | err_free_host_driver: | ||
187 | free(host_driver); | ||
188 | host_driver = NULL; | ||
189 | |||
190 | udev_unref(udev_context); | ||
191 | |||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | void usbip_host_driver_close(void) | ||
196 | { | ||
197 | if (!host_driver) | ||
198 | return; | ||
199 | |||
200 | usbip_exported_device_destroy(); | ||
201 | |||
202 | free(host_driver); | ||
203 | host_driver = NULL; | ||
204 | |||
205 | udev_unref(udev_context); | ||
206 | } | ||
207 | |||
208 | int usbip_host_refresh_device_list(void) | ||
209 | { | ||
210 | int rc; | ||
211 | |||
212 | usbip_exported_device_destroy(); | ||
213 | |||
214 | host_driver->ndevs = 0; | ||
215 | INIT_LIST_HEAD(&host_driver->edev_list); | ||
216 | |||
217 | rc = refresh_exported_devices(); | ||
218 | if (rc < 0) | ||
219 | return -1; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) | ||
225 | { | ||
226 | char attr_name[] = "usbip_sockfd"; | ||
227 | char sockfd_attr_path[SYSFS_PATH_MAX]; | ||
228 | char sockfd_buff[30]; | ||
229 | int ret; | 41 | int ret; |
230 | 42 | ||
231 | if (edev->status != SDEV_ST_AVAILABLE) { | 43 | hdriver->ndevs = 0; |
232 | dbg("device not available: %s", edev->udev.busid); | 44 | INIT_LIST_HEAD(&hdriver->edev_list); |
233 | switch (edev->status) { | ||
234 | case SDEV_ST_ERROR: | ||
235 | dbg("status SDEV_ST_ERROR"); | ||
236 | break; | ||
237 | case SDEV_ST_USED: | ||
238 | dbg("status SDEV_ST_USED"); | ||
239 | break; | ||
240 | default: | ||
241 | dbg("status unknown: 0x%x", edev->status); | ||
242 | } | ||
243 | return -1; | ||
244 | } | ||
245 | |||
246 | /* only the first interface is true */ | ||
247 | snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", | ||
248 | edev->udev.path, attr_name); | ||
249 | |||
250 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); | ||
251 | |||
252 | ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, | ||
253 | strlen(sockfd_buff)); | ||
254 | if (ret < 0) { | ||
255 | err("write_sysfs_attribute failed: sockfd %s to %s", | ||
256 | sockfd_buff, sockfd_attr_path); | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | info("connect: %s", edev->udev.busid); | ||
261 | 45 | ||
46 | ret = usbip_generic_driver_open(hdriver); | ||
47 | if (ret) | ||
48 | err("please load " USBIP_CORE_MOD_NAME ".ko and " | ||
49 | USBIP_HOST_DRV_NAME ".ko!"); | ||
262 | return ret; | 50 | return ret; |
263 | } | 51 | } |
264 | 52 | ||
265 | struct usbip_exported_device *usbip_host_get_device(int num) | 53 | struct usbip_host_driver host_driver = { |
266 | { | 54 | .edev_list = LIST_HEAD_INIT(host_driver.edev_list), |
267 | struct list_head *i; | 55 | .udev_subsystem = "usb", |
268 | struct usbip_exported_device *edev; | 56 | .ops = { |
269 | int cnt = 0; | 57 | .open = usbip_host_driver_open, |
270 | 58 | .close = usbip_generic_driver_close, | |
271 | list_for_each(i, &host_driver->edev_list) { | 59 | .refresh_device_list = usbip_generic_refresh_device_list, |
272 | edev = list_entry(i, struct usbip_exported_device, node); | 60 | .get_device = usbip_generic_get_device, |
273 | if (num == cnt) | 61 | .read_device = read_usb_device, |
274 | return edev; | 62 | .read_interface = read_usb_interface, |
275 | else | 63 | .is_my_device = is_my_device, |
276 | cnt++; | 64 | }, |
277 | } | 65 | }; |
278 | |||
279 | return NULL; | ||
280 | } | ||
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h index 2a31f855c616..77f07e72a7fe 100644 --- a/tools/usb/usbip/libsrc/usbip_host_driver.h +++ b/tools/usb/usbip/libsrc/usbip_host_driver.h | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> |
3 | * 2005-2007 Takahiro Hirofuchi | 3 | * 2005-2007 Takahiro Hirofuchi |
4 | * Copyright (C) 2015-2016 Samsung Electronics | ||
5 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
6 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
4 | * | 7 | * |
5 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -22,28 +25,8 @@ | |||
22 | #include <stdint.h> | 25 | #include <stdint.h> |
23 | #include "usbip_common.h" | 26 | #include "usbip_common.h" |
24 | #include "list.h" | 27 | #include "list.h" |
28 | #include "usbip_host_common.h" | ||
25 | 29 | ||
26 | struct usbip_host_driver { | 30 | extern struct usbip_host_driver host_driver; |
27 | int ndevs; | ||
28 | /* list of exported device */ | ||
29 | struct list_head edev_list; | ||
30 | }; | ||
31 | |||
32 | struct usbip_exported_device { | ||
33 | struct udev_device *sudev; | ||
34 | int32_t status; | ||
35 | struct usbip_usb_device udev; | ||
36 | struct list_head node; | ||
37 | struct usbip_usb_interface uinf[]; | ||
38 | }; | ||
39 | |||
40 | extern struct usbip_host_driver *host_driver; | ||
41 | |||
42 | int usbip_host_driver_open(void); | ||
43 | void usbip_host_driver_close(void); | ||
44 | |||
45 | int usbip_host_refresh_device_list(void); | ||
46 | int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd); | ||
47 | struct usbip_exported_device *usbip_host_get_device(int num); | ||
48 | 31 | ||
49 | #endif /* __USBIP_HOST_DRIVER_H */ | 32 | #endif /* __USBIP_HOST_DRIVER_H */ |
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index d58a14dfc094..70a6b507fb62 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> |
3 | * 2005-2007 Takahiro Hirofuchi | 3 | * 2005-2007 Takahiro Hirofuchi |
4 | * Copyright (C) 2015-2016 Samsung Electronics | ||
5 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
6 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
4 | * | 7 | * |
5 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -36,7 +39,8 @@ | |||
36 | static const char usbip_attach_usage_string[] = | 39 | static const char usbip_attach_usage_string[] = |
37 | "usbip attach <args>\n" | 40 | "usbip attach <args>\n" |
38 | " -r, --remote=<host> The machine with exported USB devices\n" | 41 | " -r, --remote=<host> The machine with exported USB devices\n" |
39 | " -b, --busid=<busid> Busid of the device on <host>\n"; | 42 | " -b, --busid=<busid> Busid of the device on <host>\n" |
43 | " -d, --device=<devid> Id of the virtual UDC on <host>\n"; | ||
40 | 44 | ||
41 | void usbip_attach_usage(void) | 45 | void usbip_attach_usage(void) |
42 | { | 46 | { |
@@ -203,6 +207,7 @@ int usbip_attach(int argc, char *argv[]) | |||
203 | static const struct option opts[] = { | 207 | static const struct option opts[] = { |
204 | { "remote", required_argument, NULL, 'r' }, | 208 | { "remote", required_argument, NULL, 'r' }, |
205 | { "busid", required_argument, NULL, 'b' }, | 209 | { "busid", required_argument, NULL, 'b' }, |
210 | { "device", required_argument, NULL, 'd' }, | ||
206 | { NULL, 0, NULL, 0 } | 211 | { NULL, 0, NULL, 0 } |
207 | }; | 212 | }; |
208 | char *host = NULL; | 213 | char *host = NULL; |
@@ -211,7 +216,7 @@ int usbip_attach(int argc, char *argv[]) | |||
211 | int ret = -1; | 216 | int ret = -1; |
212 | 217 | ||
213 | for (;;) { | 218 | for (;;) { |
214 | opt = getopt_long(argc, argv, "r:b:", opts, NULL); | 219 | opt = getopt_long(argc, argv, "d:r:b:", opts, NULL); |
215 | 220 | ||
216 | if (opt == -1) | 221 | if (opt == -1) |
217 | break; | 222 | break; |
@@ -220,6 +225,7 @@ int usbip_attach(int argc, char *argv[]) | |||
220 | case 'r': | 225 | case 'r': |
221 | host = optarg; | 226 | host = optarg; |
222 | break; | 227 | break; |
228 | case 'd': | ||
223 | case 'b': | 229 | case 'b': |
224 | busid = optarg; | 230 | busid = optarg; |
225 | break; | 231 | break; |
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c index d5ce34a410e7..f1b38e866dd7 100644 --- a/tools/usb/usbip/src/usbip_list.c +++ b/tools/usb/usbip/src/usbip_list.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> |
3 | * 2005-2007 Takahiro Hirofuchi | 3 | * 2005-2007 Takahiro Hirofuchi |
4 | * Copyright (C) 2015-2016 Samsung Electronics | ||
5 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
6 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
4 | * | 7 | * |
5 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -30,6 +33,10 @@ | |||
30 | #include <netdb.h> | 33 | #include <netdb.h> |
31 | #include <unistd.h> | 34 | #include <unistd.h> |
32 | 35 | ||
36 | #include <dirent.h> | ||
37 | |||
38 | #include <linux/usb/ch9.h> | ||
39 | |||
33 | #include "usbip_common.h" | 40 | #include "usbip_common.h" |
34 | #include "usbip_network.h" | 41 | #include "usbip_network.h" |
35 | #include "usbip.h" | 42 | #include "usbip.h" |
@@ -205,8 +212,10 @@ static int list_devices(bool parsable) | |||
205 | /* Get device information. */ | 212 | /* Get device information. */ |
206 | idVendor = udev_device_get_sysattr_value(dev, "idVendor"); | 213 | idVendor = udev_device_get_sysattr_value(dev, "idVendor"); |
207 | idProduct = udev_device_get_sysattr_value(dev, "idProduct"); | 214 | idProduct = udev_device_get_sysattr_value(dev, "idProduct"); |
208 | bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue"); | 215 | bConfValue = udev_device_get_sysattr_value(dev, |
209 | bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces"); | 216 | "bConfigurationValue"); |
217 | bNumIntfs = udev_device_get_sysattr_value(dev, | ||
218 | "bNumInterfaces"); | ||
210 | busid = udev_device_get_sysname(dev); | 219 | busid = udev_device_get_sysname(dev); |
211 | if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { | 220 | if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { |
212 | err("problem getting device attributes: %s", | 221 | err("problem getting device attributes: %s", |
@@ -237,12 +246,90 @@ err_out: | |||
237 | return ret; | 246 | return ret; |
238 | } | 247 | } |
239 | 248 | ||
249 | static int list_gadget_devices(bool parsable) | ||
250 | { | ||
251 | int ret = -1; | ||
252 | struct udev *udev; | ||
253 | struct udev_enumerate *enumerate; | ||
254 | struct udev_list_entry *devices, *dev_list_entry; | ||
255 | struct udev_device *dev; | ||
256 | const char *path; | ||
257 | const char *driver; | ||
258 | |||
259 | const struct usb_device_descriptor *d_desc; | ||
260 | const char *descriptors; | ||
261 | char product_name[128]; | ||
262 | |||
263 | uint16_t idVendor; | ||
264 | char idVendor_buf[8]; | ||
265 | uint16_t idProduct; | ||
266 | char idProduct_buf[8]; | ||
267 | const char *busid; | ||
268 | |||
269 | udev = udev_new(); | ||
270 | enumerate = udev_enumerate_new(udev); | ||
271 | |||
272 | udev_enumerate_add_match_subsystem(enumerate, "platform"); | ||
273 | |||
274 | udev_enumerate_scan_devices(enumerate); | ||
275 | devices = udev_enumerate_get_list_entry(enumerate); | ||
276 | |||
277 | udev_list_entry_foreach(dev_list_entry, devices) { | ||
278 | path = udev_list_entry_get_name(dev_list_entry); | ||
279 | dev = udev_device_new_from_syspath(udev, path); | ||
280 | |||
281 | driver = udev_device_get_driver(dev); | ||
282 | /* We only have mechanism to enumerate gadgets bound to vudc */ | ||
283 | if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME)) | ||
284 | continue; | ||
285 | |||
286 | /* Get device information. */ | ||
287 | descriptors = udev_device_get_sysattr_value(dev, | ||
288 | VUDC_DEVICE_DESCR_FILE); | ||
289 | |||
290 | if (!descriptors) { | ||
291 | err("problem getting device attributes: %s", | ||
292 | strerror(errno)); | ||
293 | goto err_out; | ||
294 | } | ||
295 | |||
296 | d_desc = (const struct usb_device_descriptor *) descriptors; | ||
297 | |||
298 | idVendor = le16toh(d_desc->idVendor); | ||
299 | sprintf(idVendor_buf, "0x%4x", idVendor); | ||
300 | idProduct = le16toh(d_desc->idProduct); | ||
301 | sprintf(idProduct_buf, "0x%4x", idVendor); | ||
302 | busid = udev_device_get_sysname(dev); | ||
303 | |||
304 | /* Get product name. */ | ||
305 | usbip_names_get_product(product_name, sizeof(product_name), | ||
306 | le16toh(idVendor), | ||
307 | le16toh(idProduct)); | ||
308 | |||
309 | /* Print information. */ | ||
310 | print_device(busid, idVendor_buf, idProduct_buf, parsable); | ||
311 | print_product_name(product_name, parsable); | ||
312 | |||
313 | printf("\n"); | ||
314 | |||
315 | udev_device_unref(dev); | ||
316 | } | ||
317 | ret = 0; | ||
318 | |||
319 | err_out: | ||
320 | udev_enumerate_unref(enumerate); | ||
321 | udev_unref(udev); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
240 | int usbip_list(int argc, char *argv[]) | 326 | int usbip_list(int argc, char *argv[]) |
241 | { | 327 | { |
242 | static const struct option opts[] = { | 328 | static const struct option opts[] = { |
243 | { "parsable", no_argument, NULL, 'p' }, | 329 | { "parsable", no_argument, NULL, 'p' }, |
244 | { "remote", required_argument, NULL, 'r' }, | 330 | { "remote", required_argument, NULL, 'r' }, |
245 | { "local", no_argument, NULL, 'l' }, | 331 | { "local", no_argument, NULL, 'l' }, |
332 | { "device", no_argument, NULL, 'd' }, | ||
246 | { NULL, 0, NULL, 0 } | 333 | { NULL, 0, NULL, 0 } |
247 | }; | 334 | }; |
248 | 335 | ||
@@ -254,7 +341,7 @@ int usbip_list(int argc, char *argv[]) | |||
254 | err("failed to open %s", USBIDS_FILE); | 341 | err("failed to open %s", USBIDS_FILE); |
255 | 342 | ||
256 | for (;;) { | 343 | for (;;) { |
257 | opt = getopt_long(argc, argv, "pr:l", opts, NULL); | 344 | opt = getopt_long(argc, argv, "pr:ld", opts, NULL); |
258 | 345 | ||
259 | if (opt == -1) | 346 | if (opt == -1) |
260 | break; | 347 | break; |
@@ -269,6 +356,9 @@ int usbip_list(int argc, char *argv[]) | |||
269 | case 'l': | 356 | case 'l': |
270 | ret = list_devices(parsable); | 357 | ret = list_devices(parsable); |
271 | goto out; | 358 | goto out; |
359 | case 'd': | ||
360 | ret = list_gadget_devices(parsable); | ||
361 | goto out; | ||
272 | default: | 362 | default: |
273 | goto err_out; | 363 | goto err_out; |
274 | } | 364 | } |
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c index a2e884fd9226..7bd74fb3a9cd 100644 --- a/tools/usb/usbip/src/usbip_port.c +++ b/tools/usb/usbip/src/usbip_port.c | |||
@@ -22,10 +22,13 @@ static int list_imported_devices(void) | |||
22 | struct usbip_imported_device *idev; | 22 | struct usbip_imported_device *idev; |
23 | int ret; | 23 | int ret; |
24 | 24 | ||
25 | if (usbip_names_init(USBIDS_FILE)) | ||
26 | err("failed to open %s", USBIDS_FILE); | ||
27 | |||
25 | ret = usbip_vhci_driver_open(); | 28 | ret = usbip_vhci_driver_open(); |
26 | if (ret < 0) { | 29 | if (ret < 0) { |
27 | err("open vhci_driver"); | 30 | err("open vhci_driver"); |
28 | return -1; | 31 | goto err_names_free; |
29 | } | 32 | } |
30 | 33 | ||
31 | printf("Imported USB devices\n"); | 34 | printf("Imported USB devices\n"); |
@@ -35,13 +38,19 @@ static int list_imported_devices(void) | |||
35 | idev = &vhci_driver->idev[i]; | 38 | idev = &vhci_driver->idev[i]; |
36 | 39 | ||
37 | if (usbip_vhci_imported_device_dump(idev) < 0) | 40 | if (usbip_vhci_imported_device_dump(idev) < 0) |
38 | ret = -1; | 41 | goto err_driver_close; |
39 | } | 42 | } |
40 | 43 | ||
41 | usbip_vhci_driver_close(); | 44 | usbip_vhci_driver_close(); |
45 | usbip_names_free(); | ||
42 | 46 | ||
43 | return ret; | 47 | return ret; |
44 | 48 | ||
49 | err_driver_close: | ||
50 | usbip_vhci_driver_close(); | ||
51 | err_names_free: | ||
52 | usbip_names_free(); | ||
53 | return -1; | ||
45 | } | 54 | } |
46 | 55 | ||
47 | int usbip_port_show(__attribute__((unused)) int argc, | 56 | int usbip_port_show(__attribute__((unused)) int argc, |
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index 2a7cd2b8d966..a0972dea9e6c 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | 2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> |
3 | * 2005-2007 Takahiro Hirofuchi | 3 | * 2005-2007 Takahiro Hirofuchi |
4 | * Copyright (C) 2015-2016 Samsung Electronics | ||
5 | * Igor Kotrasinski <i.kotrasinsk@samsung.com> | ||
6 | * Krzysztof Opasiak <k.opasiak@samsung.com> | ||
4 | * | 7 | * |
5 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -41,6 +44,8 @@ | |||
41 | #include <poll.h> | 44 | #include <poll.h> |
42 | 45 | ||
43 | #include "usbip_host_driver.h" | 46 | #include "usbip_host_driver.h" |
47 | #include "usbip_host_common.h" | ||
48 | #include "usbip_device_driver.h" | ||
44 | #include "usbip_common.h" | 49 | #include "usbip_common.h" |
45 | #include "usbip_network.h" | 50 | #include "usbip_network.h" |
46 | #include "list.h" | 51 | #include "list.h" |
@@ -64,6 +69,11 @@ static const char usbipd_help_string[] = | |||
64 | " -6, --ipv6\n" | 69 | " -6, --ipv6\n" |
65 | " Bind to IPv6. Default is both.\n" | 70 | " Bind to IPv6. Default is both.\n" |
66 | "\n" | 71 | "\n" |
72 | " -e, --device\n" | ||
73 | " Run in device mode.\n" | ||
74 | " Rather than drive an attached device, create\n" | ||
75 | " a virtual UDC to bind gadgets to.\n" | ||
76 | "\n" | ||
67 | " -D, --daemon\n" | 77 | " -D, --daemon\n" |
68 | " Run as a daemon process.\n" | 78 | " Run as a daemon process.\n" |
69 | "\n" | 79 | "\n" |
@@ -83,6 +93,8 @@ static const char usbipd_help_string[] = | |||
83 | " -v, --version\n" | 93 | " -v, --version\n" |
84 | " Show version.\n"; | 94 | " Show version.\n"; |
85 | 95 | ||
96 | static struct usbip_host_driver *driver; | ||
97 | |||
86 | static void usbipd_help(void) | 98 | static void usbipd_help(void) |
87 | { | 99 | { |
88 | printf("%s\n", usbipd_help_string); | 100 | printf("%s\n", usbipd_help_string); |
@@ -107,7 +119,7 @@ static int recv_request_import(int sockfd) | |||
107 | } | 119 | } |
108 | PACK_OP_IMPORT_REQUEST(0, &req); | 120 | PACK_OP_IMPORT_REQUEST(0, &req); |
109 | 121 | ||
110 | list_for_each(i, &host_driver->edev_list) { | 122 | list_for_each(i, &driver->edev_list) { |
111 | edev = list_entry(i, struct usbip_exported_device, node); | 123 | edev = list_entry(i, struct usbip_exported_device, node); |
112 | if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { | 124 | if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { |
113 | info("found requested device: %s", req.busid); | 125 | info("found requested device: %s", req.busid); |
@@ -121,7 +133,7 @@ static int recv_request_import(int sockfd) | |||
121 | usbip_net_set_nodelay(sockfd); | 133 | usbip_net_set_nodelay(sockfd); |
122 | 134 | ||
123 | /* export device needs a TCP/IP socket descriptor */ | 135 | /* export device needs a TCP/IP socket descriptor */ |
124 | rc = usbip_host_export_device(edev, sockfd); | 136 | rc = usbip_export_device(edev, sockfd); |
125 | if (rc < 0) | 137 | if (rc < 0) |
126 | error = 1; | 138 | error = 1; |
127 | } else { | 139 | } else { |
@@ -166,7 +178,7 @@ static int send_reply_devlist(int connfd) | |||
166 | 178 | ||
167 | reply.ndev = 0; | 179 | reply.ndev = 0; |
168 | /* number of exported devices */ | 180 | /* number of exported devices */ |
169 | list_for_each(j, &host_driver->edev_list) { | 181 | list_for_each(j, &driver->edev_list) { |
170 | reply.ndev += 1; | 182 | reply.ndev += 1; |
171 | } | 183 | } |
172 | info("exportable devices: %d", reply.ndev); | 184 | info("exportable devices: %d", reply.ndev); |
@@ -184,7 +196,7 @@ static int send_reply_devlist(int connfd) | |||
184 | return -1; | 196 | return -1; |
185 | } | 197 | } |
186 | 198 | ||
187 | list_for_each(j, &host_driver->edev_list) { | 199 | list_for_each(j, &driver->edev_list) { |
188 | edev = list_entry(j, struct usbip_exported_device, node); | 200 | edev = list_entry(j, struct usbip_exported_device, node); |
189 | dump_usb_device(&edev->udev); | 201 | dump_usb_device(&edev->udev); |
190 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); | 202 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); |
@@ -246,7 +258,7 @@ static int recv_pdu(int connfd) | |||
246 | return -1; | 258 | return -1; |
247 | } | 259 | } |
248 | 260 | ||
249 | ret = usbip_host_refresh_device_list(); | 261 | ret = usbip_refresh_device_list(driver); |
250 | if (ret < 0) { | 262 | if (ret < 0) { |
251 | dbg("could not refresh device list: %d", ret); | 263 | dbg("could not refresh device list: %d", ret); |
252 | return -1; | 264 | return -1; |
@@ -491,16 +503,13 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6) | |||
491 | struct timespec timeout; | 503 | struct timespec timeout; |
492 | sigset_t sigmask; | 504 | sigset_t sigmask; |
493 | 505 | ||
494 | if (usbip_host_driver_open()) { | 506 | if (usbip_driver_open(driver)) |
495 | err("please load " USBIP_CORE_MOD_NAME ".ko and " | ||
496 | USBIP_HOST_DRV_NAME ".ko!"); | ||
497 | return -1; | 507 | return -1; |
498 | } | ||
499 | 508 | ||
500 | if (daemonize) { | 509 | if (daemonize) { |
501 | if (daemon(0, 0) < 0) { | 510 | if (daemon(0, 0) < 0) { |
502 | err("daemonizing failed: %s", strerror(errno)); | 511 | err("daemonizing failed: %s", strerror(errno)); |
503 | usbip_host_driver_close(); | 512 | usbip_driver_close(driver); |
504 | return -1; | 513 | return -1; |
505 | } | 514 | } |
506 | umask(0); | 515 | umask(0); |
@@ -525,7 +534,7 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6) | |||
525 | 534 | ||
526 | ai_head = do_getaddrinfo(NULL, family); | 535 | ai_head = do_getaddrinfo(NULL, family); |
527 | if (!ai_head) { | 536 | if (!ai_head) { |
528 | usbip_host_driver_close(); | 537 | usbip_driver_close(driver); |
529 | return -1; | 538 | return -1; |
530 | } | 539 | } |
531 | nsockfd = listen_all_addrinfo(ai_head, sockfdlist, | 540 | nsockfd = listen_all_addrinfo(ai_head, sockfdlist, |
@@ -533,7 +542,7 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6) | |||
533 | freeaddrinfo(ai_head); | 542 | freeaddrinfo(ai_head); |
534 | if (nsockfd <= 0) { | 543 | if (nsockfd <= 0) { |
535 | err("failed to open a listening socket"); | 544 | err("failed to open a listening socket"); |
536 | usbip_host_driver_close(); | 545 | usbip_driver_close(driver); |
537 | return -1; | 546 | return -1; |
538 | } | 547 | } |
539 | 548 | ||
@@ -574,7 +583,7 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6) | |||
574 | 583 | ||
575 | info("shutting down " PROGNAME); | 584 | info("shutting down " PROGNAME); |
576 | free(fds); | 585 | free(fds); |
577 | usbip_host_driver_close(); | 586 | usbip_driver_close(driver); |
578 | 587 | ||
579 | return 0; | 588 | return 0; |
580 | } | 589 | } |
@@ -587,6 +596,7 @@ int main(int argc, char *argv[]) | |||
587 | { "daemon", no_argument, NULL, 'D' }, | 596 | { "daemon", no_argument, NULL, 'D' }, |
588 | { "daemon", no_argument, NULL, 'D' }, | 597 | { "daemon", no_argument, NULL, 'D' }, |
589 | { "debug", no_argument, NULL, 'd' }, | 598 | { "debug", no_argument, NULL, 'd' }, |
599 | { "device", no_argument, NULL, 'e' }, | ||
590 | { "pid", optional_argument, NULL, 'P' }, | 600 | { "pid", optional_argument, NULL, 'P' }, |
591 | { "tcp-port", required_argument, NULL, 't' }, | 601 | { "tcp-port", required_argument, NULL, 't' }, |
592 | { "help", no_argument, NULL, 'h' }, | 602 | { "help", no_argument, NULL, 'h' }, |
@@ -613,8 +623,9 @@ int main(int argc, char *argv[]) | |||
613 | err("not running as root?"); | 623 | err("not running as root?"); |
614 | 624 | ||
615 | cmd = cmd_standalone_mode; | 625 | cmd = cmd_standalone_mode; |
626 | driver = &host_driver; | ||
616 | for (;;) { | 627 | for (;;) { |
617 | opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL); | 628 | opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL); |
618 | 629 | ||
619 | if (opt == -1) | 630 | if (opt == -1) |
620 | break; | 631 | break; |
@@ -644,6 +655,9 @@ int main(int argc, char *argv[]) | |||
644 | case 'v': | 655 | case 'v': |
645 | cmd = cmd_version; | 656 | cmd = cmd_version; |
646 | break; | 657 | break; |
658 | case 'e': | ||
659 | driver = &device_driver; | ||
660 | break; | ||
647 | case '?': | 661 | case '?': |
648 | usbipd_help(); | 662 | usbipd_help(); |
649 | default: | 663 | default: |
diff --git a/tools/virtio/ringtest/Makefile b/tools/virtio/ringtest/Makefile index feaa64ac4630..6ba745529833 100644 --- a/tools/virtio/ringtest/Makefile +++ b/tools/virtio/ringtest/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | all: | 1 | all: |
2 | 2 | ||
3 | all: ring virtio_ring_0_9 virtio_ring_poll | 3 | all: ring virtio_ring_0_9 virtio_ring_poll virtio_ring_inorder |
4 | 4 | ||
5 | CFLAGS += -Wall | 5 | CFLAGS += -Wall |
6 | CFLAGS += -pthread -O2 -ggdb | 6 | CFLAGS += -pthread -O2 -ggdb |
@@ -10,13 +10,16 @@ main.o: main.c main.h | |||
10 | ring.o: ring.c main.h | 10 | ring.o: ring.c main.h |
11 | virtio_ring_0_9.o: virtio_ring_0_9.c main.h | 11 | virtio_ring_0_9.o: virtio_ring_0_9.c main.h |
12 | virtio_ring_poll.o: virtio_ring_poll.c virtio_ring_0_9.c main.h | 12 | virtio_ring_poll.o: virtio_ring_poll.c virtio_ring_0_9.c main.h |
13 | virtio_ring_inorder.o: virtio_ring_inorder.c virtio_ring_0_9.c main.h | ||
13 | ring: ring.o main.o | 14 | ring: ring.o main.o |
14 | virtio_ring_0_9: virtio_ring_0_9.o main.o | 15 | virtio_ring_0_9: virtio_ring_0_9.o main.o |
15 | virtio_ring_poll: virtio_ring_poll.o main.o | 16 | virtio_ring_poll: virtio_ring_poll.o main.o |
17 | virtio_ring_inorder: virtio_ring_inorder.o main.o | ||
16 | clean: | 18 | clean: |
17 | -rm main.o | 19 | -rm main.o |
18 | -rm ring.o ring | 20 | -rm ring.o ring |
19 | -rm virtio_ring_0_9.o virtio_ring_0_9 | 21 | -rm virtio_ring_0_9.o virtio_ring_0_9 |
20 | -rm virtio_ring_poll.o virtio_ring_poll | 22 | -rm virtio_ring_poll.o virtio_ring_poll |
23 | -rm virtio_ring_inorder.o virtio_ring_inorder | ||
21 | 24 | ||
22 | .PHONY: all clean | 25 | .PHONY: all clean |
diff --git a/tools/virtio/ringtest/main.c b/tools/virtio/ringtest/main.c index 3a5ff438bd62..147abb452a6c 100644 --- a/tools/virtio/ringtest/main.c +++ b/tools/virtio/ringtest/main.c | |||
@@ -115,7 +115,7 @@ static void run_guest(void) | |||
115 | do { | 115 | do { |
116 | if (started < bufs && | 116 | if (started < bufs && |
117 | started - completed < max_outstanding) { | 117 | started - completed < max_outstanding) { |
118 | r = add_inbuf(0, NULL, "Hello, world!"); | 118 | r = add_inbuf(0, "Buffer\n", "Hello, world!"); |
119 | if (__builtin_expect(r == 0, true)) { | 119 | if (__builtin_expect(r == 0, true)) { |
120 | ++started; | 120 | ++started; |
121 | if (!--tokick) { | 121 | if (!--tokick) { |
diff --git a/tools/virtio/ringtest/virtio_ring_0_9.c b/tools/virtio/ringtest/virtio_ring_0_9.c index 47c9a1a18d36..761866212aac 100644 --- a/tools/virtio/ringtest/virtio_ring_0_9.c +++ b/tools/virtio/ringtest/virtio_ring_0_9.c | |||
@@ -26,6 +26,14 @@ struct vring ring; | |||
26 | * high bits of ring id ^ 0x8000). | 26 | * high bits of ring id ^ 0x8000). |
27 | */ | 27 | */ |
28 | /* #ifdef RING_POLL */ | 28 | /* #ifdef RING_POLL */ |
29 | /* enabling the below activates experimental in-order code | ||
30 | * (which skips ring updates and reads and writes len in descriptor). | ||
31 | */ | ||
32 | /* #ifdef INORDER */ | ||
33 | |||
34 | #if defined(RING_POLL) && defined(INORDER) | ||
35 | #error "RING_POLL and INORDER are mutually exclusive" | ||
36 | #endif | ||
29 | 37 | ||
30 | /* how much padding is needed to avoid false cache sharing */ | 38 | /* how much padding is needed to avoid false cache sharing */ |
31 | #define HOST_GUEST_PADDING 0x80 | 39 | #define HOST_GUEST_PADDING 0x80 |
@@ -35,7 +43,11 @@ struct guest { | |||
35 | unsigned short last_used_idx; | 43 | unsigned short last_used_idx; |
36 | unsigned short num_free; | 44 | unsigned short num_free; |
37 | unsigned short kicked_avail_idx; | 45 | unsigned short kicked_avail_idx; |
46 | #ifndef INORDER | ||
38 | unsigned short free_head; | 47 | unsigned short free_head; |
48 | #else | ||
49 | unsigned short reserved_free_head; | ||
50 | #endif | ||
39 | unsigned char reserved[HOST_GUEST_PADDING - 10]; | 51 | unsigned char reserved[HOST_GUEST_PADDING - 10]; |
40 | } guest; | 52 | } guest; |
41 | 53 | ||
@@ -66,8 +78,10 @@ void alloc_ring(void) | |||
66 | guest.avail_idx = 0; | 78 | guest.avail_idx = 0; |
67 | guest.kicked_avail_idx = -1; | 79 | guest.kicked_avail_idx = -1; |
68 | guest.last_used_idx = 0; | 80 | guest.last_used_idx = 0; |
81 | #ifndef INORDER | ||
69 | /* Put everything in free lists. */ | 82 | /* Put everything in free lists. */ |
70 | guest.free_head = 0; | 83 | guest.free_head = 0; |
84 | #endif | ||
71 | for (i = 0; i < ring_size - 1; i++) | 85 | for (i = 0; i < ring_size - 1; i++) |
72 | ring.desc[i].next = i + 1; | 86 | ring.desc[i].next = i + 1; |
73 | host.used_idx = 0; | 87 | host.used_idx = 0; |
@@ -84,13 +98,20 @@ void alloc_ring(void) | |||
84 | /* guest side */ | 98 | /* guest side */ |
85 | int add_inbuf(unsigned len, void *buf, void *datap) | 99 | int add_inbuf(unsigned len, void *buf, void *datap) |
86 | { | 100 | { |
87 | unsigned head, avail; | 101 | unsigned head; |
102 | #ifndef INORDER | ||
103 | unsigned avail; | ||
104 | #endif | ||
88 | struct vring_desc *desc; | 105 | struct vring_desc *desc; |
89 | 106 | ||
90 | if (!guest.num_free) | 107 | if (!guest.num_free) |
91 | return -1; | 108 | return -1; |
92 | 109 | ||
110 | #ifdef INORDER | ||
111 | head = (ring_size - 1) & (guest.avail_idx++); | ||
112 | #else | ||
93 | head = guest.free_head; | 113 | head = guest.free_head; |
114 | #endif | ||
94 | guest.num_free--; | 115 | guest.num_free--; |
95 | 116 | ||
96 | desc = ring.desc; | 117 | desc = ring.desc; |
@@ -102,7 +123,9 @@ int add_inbuf(unsigned len, void *buf, void *datap) | |||
102 | * descriptors. | 123 | * descriptors. |
103 | */ | 124 | */ |
104 | desc[head].flags &= ~VRING_DESC_F_NEXT; | 125 | desc[head].flags &= ~VRING_DESC_F_NEXT; |
126 | #ifndef INORDER | ||
105 | guest.free_head = desc[head].next; | 127 | guest.free_head = desc[head].next; |
128 | #endif | ||
106 | 129 | ||
107 | data[head].data = datap; | 130 | data[head].data = datap; |
108 | 131 | ||
@@ -113,8 +136,12 @@ int add_inbuf(unsigned len, void *buf, void *datap) | |||
113 | ring.avail->ring[avail & (ring_size - 1)] = | 136 | ring.avail->ring[avail & (ring_size - 1)] = |
114 | (head | (avail & ~(ring_size - 1))) ^ 0x8000; | 137 | (head | (avail & ~(ring_size - 1))) ^ 0x8000; |
115 | #else | 138 | #else |
139 | #ifndef INORDER | ||
140 | /* Barrier A (for pairing) */ | ||
141 | smp_release(); | ||
116 | avail = (ring_size - 1) & (guest.avail_idx++); | 142 | avail = (ring_size - 1) & (guest.avail_idx++); |
117 | ring.avail->ring[avail] = head; | 143 | ring.avail->ring[avail] = head; |
144 | #endif | ||
118 | /* Barrier A (for pairing) */ | 145 | /* Barrier A (for pairing) */ |
119 | smp_release(); | 146 | smp_release(); |
120 | #endif | 147 | #endif |
@@ -141,15 +168,27 @@ void *get_buf(unsigned *lenp, void **bufp) | |||
141 | return NULL; | 168 | return NULL; |
142 | /* Barrier B (for pairing) */ | 169 | /* Barrier B (for pairing) */ |
143 | smp_acquire(); | 170 | smp_acquire(); |
171 | #ifdef INORDER | ||
172 | head = (ring_size - 1) & guest.last_used_idx; | ||
173 | index = head; | ||
174 | #else | ||
144 | head = (ring_size - 1) & guest.last_used_idx; | 175 | head = (ring_size - 1) & guest.last_used_idx; |
145 | index = ring.used->ring[head].id; | 176 | index = ring.used->ring[head].id; |
146 | #endif | 177 | #endif |
178 | |||
179 | #endif | ||
180 | #ifdef INORDER | ||
181 | *lenp = ring.desc[index].len; | ||
182 | #else | ||
147 | *lenp = ring.used->ring[head].len; | 183 | *lenp = ring.used->ring[head].len; |
184 | #endif | ||
148 | datap = data[index].data; | 185 | datap = data[index].data; |
149 | *bufp = (void*)(unsigned long)ring.desc[index].addr; | 186 | *bufp = (void*)(unsigned long)ring.desc[index].addr; |
150 | data[index].data = NULL; | 187 | data[index].data = NULL; |
188 | #ifndef INORDER | ||
151 | ring.desc[index].next = guest.free_head; | 189 | ring.desc[index].next = guest.free_head; |
152 | guest.free_head = index; | 190 | guest.free_head = index; |
191 | #endif | ||
153 | guest.num_free++; | 192 | guest.num_free++; |
154 | guest.last_used_idx++; | 193 | guest.last_used_idx++; |
155 | return datap; | 194 | return datap; |
@@ -283,16 +322,24 @@ bool use_buf(unsigned *lenp, void **bufp) | |||
283 | smp_acquire(); | 322 | smp_acquire(); |
284 | 323 | ||
285 | used_idx &= ring_size - 1; | 324 | used_idx &= ring_size - 1; |
325 | #ifdef INORDER | ||
326 | head = used_idx; | ||
327 | #else | ||
286 | head = ring.avail->ring[used_idx]; | 328 | head = ring.avail->ring[used_idx]; |
329 | #endif | ||
287 | desc = &ring.desc[head]; | 330 | desc = &ring.desc[head]; |
288 | #endif | 331 | #endif |
289 | 332 | ||
290 | *lenp = desc->len; | 333 | *lenp = desc->len; |
291 | *bufp = (void *)(unsigned long)desc->addr; | 334 | *bufp = (void *)(unsigned long)desc->addr; |
292 | 335 | ||
336 | #ifdef INORDER | ||
337 | desc->len = desc->len - 1; | ||
338 | #else | ||
293 | /* now update used ring */ | 339 | /* now update used ring */ |
294 | ring.used->ring[used_idx].id = head; | 340 | ring.used->ring[used_idx].id = head; |
295 | ring.used->ring[used_idx].len = desc->len - 1; | 341 | ring.used->ring[used_idx].len = desc->len - 1; |
342 | #endif | ||
296 | /* Barrier B (for pairing) */ | 343 | /* Barrier B (for pairing) */ |
297 | smp_release(); | 344 | smp_release(); |
298 | host.used_idx++; | 345 | host.used_idx++; |
diff --git a/tools/virtio/ringtest/virtio_ring_inorder.c b/tools/virtio/ringtest/virtio_ring_inorder.c new file mode 100644 index 000000000000..2438ca58a2ad --- /dev/null +++ b/tools/virtio/ringtest/virtio_ring_inorder.c | |||
@@ -0,0 +1,2 @@ | |||
1 | #define INORDER 1 | ||
2 | #include "virtio_ring_0_9.c" | ||