pm_rps: Load helper should stall for last write
[platform/upstream/intel-gpu-tools.git] / tests / pm_rps.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Ben Widawsky <ben@bwidawsk.net>
25  *    Jeff McGee <jeff.mcgee@intel.com>
26  *
27  */
28
29 #define _GNU_SOURCE
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <getopt.h>
35 #include <fcntl.h>
36 #include "drmtest.h"
37 #include "intel_gpu_tools.h"
38 #include "intel_bufmgr.h"
39 #include "intel_batchbuffer.h"
40 #include "igt_debugfs.h"
41
42 static bool verbose = false;
43
44 static int drm_fd;
45
46 static const char sysfs_base_path[] = "/sys/class/drm/card%d/gt_%s_freq_mhz";
47 enum {
48         CUR,
49         MIN,
50         MAX,
51         RP0,
52         RP1,
53         RPn,
54         NUMFREQ
55 };
56
57 static int origfreqs[NUMFREQ];
58
59 struct junk {
60         const char *name;
61         const char *mode;
62         FILE *filp;
63 } stuff[] = {
64         { "cur", "r", NULL }, { "min", "rb+", NULL }, { "max", "rb+", NULL }, { "RP0", "r", NULL }, { "RP1", "r", NULL }, { "RPn", "r", NULL }, { NULL, NULL, NULL }
65 };
66
67 static igt_debugfs_t dfs;
68
69 static int readval(FILE *filp)
70 {
71         int val;
72         int scanned;
73
74         rewind(filp);
75         scanned = fscanf(filp, "%d", &val);
76         igt_assert(scanned == 1);
77
78         return val;
79 }
80
81 static void read_freqs(int *freqs)
82 {
83         int i;
84
85         for (i = 0; i < NUMFREQ; i++)
86                 freqs[i] = readval(stuff[i].filp);
87 }
88
89 static int do_writeval(FILE *filp, int val, int lerrno)
90 {
91         int ret, orig;
92
93         orig = readval(filp);
94         rewind(filp);
95         ret = fprintf(filp, "%d", val);
96
97         if (lerrno) {
98                 /* Expecting specific error */
99                 igt_assert(ret == EOF && errno == lerrno);
100                 igt_assert(readval(filp) == orig);
101         } else {
102                 /* Expecting no error */
103                 igt_assert(ret != EOF);
104                 igt_assert(readval(filp) == val);
105         }
106
107         return ret;
108 }
109 #define writeval(filp, val) do_writeval(filp, val, 0)
110 #define writeval_inval(filp, val) do_writeval(filp, val, EINVAL)
111
112 static void setfreq(int val)
113 {
114         if (val > readval(stuff[MAX].filp)) {
115                 writeval(stuff[MAX].filp, val);
116                 writeval(stuff[MIN].filp, val);
117         } else {
118                 writeval(stuff[MIN].filp, val);
119                 writeval(stuff[MAX].filp, val);
120         }
121 }
122
123 static void checkit(const int *freqs)
124 {
125         igt_assert(freqs[MIN] <= freqs[MAX]);
126         igt_assert(freqs[CUR] <= freqs[MAX]);
127         igt_assert(freqs[MIN] <= freqs[CUR]);
128         igt_assert(freqs[RPn] <= freqs[MIN]);
129         igt_assert(freqs[MAX] <= freqs[RP0]);
130         igt_assert(freqs[RP1] <= freqs[RP0]);
131         igt_assert(freqs[RPn] <= freqs[RP1]);
132         igt_assert(freqs[RP0] != 0);
133         igt_assert(freqs[RP1] != 0);
134 }
135
136 static void dumpit(const int *freqs)
137 {
138         int i;
139
140         printf("gt freq (MHz):");
141         for (i = 0; i < NUMFREQ; i++)
142                 printf("  %s=%d", stuff[i].name, freqs[i]);
143
144         printf("\n");
145 }
146 #define dump(x) if (verbose) dumpit(x)
147 #define log(...) if (verbose) printf(__VA_ARGS__)
148
149 static struct load_helper {
150         int devid;
151         int has_ppgtt;
152         drm_intel_bufmgr *bufmgr;
153         struct intel_batchbuffer *batch;
154         drm_intel_bo *target_buffer;
155         bool ready;
156         bool exit;
157         struct igt_helper_process igt_proc;
158 } lh;
159
160 static void load_helper_signal_handler(int sig)
161 {
162         lh.exit = true;
163 }
164
165 static void emit_store_dword_imm(uint32_t val)
166 {
167         int cmd;
168         struct intel_batchbuffer *batch = lh.batch;
169
170         cmd = MI_STORE_DWORD_IMM;
171         if (!lh.has_ppgtt)
172                 cmd |= MI_MEM_VIRTUAL;
173
174         if (intel_gen(lh.devid) >= 8) {
175                 BEGIN_BATCH(4);
176                 OUT_BATCH(cmd);
177                 OUT_RELOC(lh.target_buffer, I915_GEM_DOMAIN_INSTRUCTION,
178                           I915_GEM_DOMAIN_INSTRUCTION, 0);
179                 OUT_BATCH(0);
180                 OUT_BATCH(val);
181                 ADVANCE_BATCH();
182         } else {
183                 BEGIN_BATCH(4);
184                 OUT_BATCH(cmd);
185                 OUT_BATCH(0); /* reserved */
186                 OUT_RELOC(lh.target_buffer, I915_GEM_DOMAIN_INSTRUCTION,
187                           I915_GEM_DOMAIN_INSTRUCTION, 0);
188                 OUT_BATCH(val);
189                 ADVANCE_BATCH();
190         }
191 }
192
193 static void load_helper_run(void)
194 {
195         assert(!lh.igt_proc.running);
196
197         igt_require(lh.ready == true);
198
199         igt_fork_helper(&lh.igt_proc) {
200                 uint32_t val = 0;
201
202                 signal(SIGUSR1, load_helper_signal_handler);
203
204                 while (!lh.exit) {
205                         emit_store_dword_imm(val);
206                         intel_batchbuffer_flush_on_ring(lh.batch, 0);
207                         val++;
208                 }
209
210                 /* Map buffer to stall for write completion */
211                 drm_intel_bo_map(lh.target_buffer, 0);
212                 drm_intel_bo_unmap(lh.target_buffer);
213
214                 log("load helper sent %u dword writes\n", val);
215         }
216 }
217
218 static void load_helper_stop(void)
219 {
220         assert(lh.igt_proc.running);
221         kill(lh.igt_proc.pid, SIGUSR1);
222         igt_wait_helper(&lh.igt_proc);
223 }
224
225 /* The load helper resource is used by only some subtests. We attempt to
226  * initialize in igt_fixture but do our igt_require check only if a
227  * subtest attempts to run it */
228 static void load_helper_init(void)
229 {
230         lh.devid = intel_get_drm_devid(drm_fd);
231         lh.has_ppgtt = gem_uses_aliasing_ppgtt(drm_fd);
232
233         /* MI_STORE_DATA can only use GTT address on gen4+/g33 and needs
234          * snoopable mem on pre-gen6. */
235         if (intel_gen(lh.devid) < 6) {
236                 log("load helper init failed: pre-gen6 not supported\n");
237                 return;
238         }
239
240         lh.bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
241         if (!lh.bufmgr) {
242                 log("load helper init failed: buffer manager init\n");
243                 return;
244         }
245         drm_intel_bufmgr_gem_enable_reuse(lh.bufmgr);
246
247         lh.batch = intel_batchbuffer_alloc(lh.bufmgr, lh.devid);
248         if (!lh.batch) {
249                 log("load helper init failed: batch buffer alloc\n");
250                 return;
251         }
252
253         lh.target_buffer = drm_intel_bo_alloc(lh.bufmgr, "target bo",
254                                               4096, 4096);
255         if (!lh.target_buffer) {
256                 log("load helper init failed: target buffer alloc\n");
257                 return;
258         }
259
260         lh.ready = true;
261 }
262
263 static void load_helper_deinit(void)
264 {
265         if (lh.igt_proc.running)
266                 load_helper_stop();
267
268         if (lh.target_buffer)
269                 drm_intel_bo_unreference(lh.target_buffer);
270
271         if (lh.batch)
272                 intel_batchbuffer_free(lh.batch);
273
274         if (lh.bufmgr)
275                 drm_intel_bufmgr_destroy(lh.bufmgr);
276 }
277
278 static void stop_rings(void)
279 {
280         int fd;
281         static const char data[] = "0xf";
282
283         fd = igt_debugfs_open(&dfs, "i915_ring_stop", O_WRONLY);
284         igt_assert(fd >= 0);
285
286         log("injecting ring stop\n");
287         igt_assert(write(fd, data, sizeof(data)) == sizeof(data));
288
289         close(fd);
290 }
291
292 static bool rings_stopped(void)
293 {
294         int fd;
295         static char buf[128];
296         unsigned long long val;
297
298         fd = igt_debugfs_open(&dfs, "i915_ring_stop", O_RDONLY);
299         igt_assert(fd >= 0);
300
301         igt_assert(read(fd, buf, sizeof(buf)) > 0);
302         close(fd);
303
304         sscanf(buf, "%llx", &val);
305
306         return (bool)val;
307 }
308
309 static void min_max_config(void (*check)(void))
310 {
311         int fmid = (origfreqs[RPn] + origfreqs[RP0]) / 2;
312
313         log("\nCheck original min and max...\n");
314         check();
315
316         log("\nSet min=RPn and max=RP0...\n");
317         writeval(stuff[MIN].filp, origfreqs[RPn]);
318         writeval(stuff[MAX].filp, origfreqs[RP0]);
319         check();
320
321         log("\nIncrease min to midpoint...\n");
322         writeval(stuff[MIN].filp, fmid);
323         check();
324
325         log("\nIncrease min to RP0...\n");
326         writeval(stuff[MIN].filp, origfreqs[RP0]);
327         check();
328
329         log("\nIncrease min above RP0 (invalid)...\n");
330         writeval_inval(stuff[MIN].filp, origfreqs[RP0] + 1000);
331         check();
332
333         log("\nDecrease max to RPn (invalid)...\n");
334         writeval_inval(stuff[MAX].filp, origfreqs[RPn]);
335         check();
336
337         log("\nDecrease min to midpoint...\n");
338         writeval(stuff[MIN].filp, fmid);
339         check();
340
341         log("\nDecrease min to RPn...\n");
342         writeval(stuff[MIN].filp, origfreqs[RPn]);
343         check();
344
345         log("\nDecrease min below RPn (invalid)...\n");
346         writeval_inval(stuff[MIN].filp, 0);
347         check();
348
349         log("\nDecrease max to midpoint...\n");
350         writeval(stuff[MAX].filp, fmid);
351         check();
352
353         log("\nDecrease max to RPn...\n");
354         writeval(stuff[MAX].filp, origfreqs[RPn]);
355         check();
356
357         log("\nDecrease max below RPn (invalid)...\n");
358         writeval_inval(stuff[MAX].filp, 0);
359         check();
360
361         log("\nIncrease min to RP0 (invalid)...\n");
362         writeval_inval(stuff[MIN].filp, origfreqs[RP0]);
363         check();
364
365         log("\nIncrease max to midpoint...\n");
366         writeval(stuff[MAX].filp, fmid);
367         check();
368
369         log("\nIncrease max to RP0...\n");
370         writeval(stuff[MAX].filp, origfreqs[RP0]);
371         check();
372
373         log("\nIncrease max above RP0 (invalid)...\n");
374         writeval_inval(stuff[MAX].filp, origfreqs[RP0] + 1000);
375         check();
376
377         writeval(stuff[MIN].filp, origfreqs[MIN]);
378         writeval(stuff[MAX].filp, origfreqs[MAX]);
379 }
380
381 static void basic_check(void)
382 {
383         int freqs[NUMFREQ];
384
385         read_freqs(freqs);
386         dump(freqs);
387         checkit(freqs);
388 }
389
390 #define IDLE_WAIT_TIMESTEP_MSEC 100
391 #define IDLE_WAIT_TIMEOUT_MSEC 3000
392 static void idle_check(void)
393 {
394         int freqs[NUMFREQ];
395         int wait = 0;
396
397         /* Monitor frequencies until cur settles down to min, which should
398          * happen within the allotted time */
399         do {
400                 read_freqs(freqs);
401                 dump(freqs);
402                 checkit(freqs);
403                 if (freqs[CUR] == freqs[MIN])
404                         break;
405                 usleep(1000 * IDLE_WAIT_TIMESTEP_MSEC);
406                 wait += IDLE_WAIT_TIMESTEP_MSEC;
407         } while (wait < IDLE_WAIT_TIMEOUT_MSEC);
408
409         igt_assert(freqs[CUR] == freqs[MIN]);
410         log("Required %d msec to reach cur=min\n", wait);
411 }
412
413 #define LOADED_WAIT_TIMESTEP_MSEC 100
414 #define LOADED_WAIT_TIMEOUT_MSEC 3000
415 static void loaded_check(void)
416 {
417         int freqs[NUMFREQ];
418         int wait = 0;
419
420         /* Monitor frequencies until cur increases to max, which should
421          * happen within the allotted time */
422         do {
423                 read_freqs(freqs);
424                 dump(freqs);
425                 checkit(freqs);
426                 if (freqs[CUR] == freqs[MAX])
427                         break;
428                 usleep(1000 * LOADED_WAIT_TIMESTEP_MSEC);
429                 wait += LOADED_WAIT_TIMESTEP_MSEC;
430         } while (wait < LOADED_WAIT_TIMEOUT_MSEC);
431
432         igt_assert(freqs[CUR] == freqs[MAX]);
433         log("Required %d msec to reach cur=max\n", wait);
434 }
435
436 static void pm_rps_exit_handler(int sig)
437 {
438         if (origfreqs[MIN] > readval(stuff[MAX].filp)) {
439                 writeval(stuff[MAX].filp, origfreqs[MAX]);
440                 writeval(stuff[MIN].filp, origfreqs[MIN]);
441         } else {
442                 writeval(stuff[MIN].filp, origfreqs[MIN]);
443                 writeval(stuff[MAX].filp, origfreqs[MAX]);
444         }
445
446         load_helper_deinit();
447         close(drm_fd);
448 }
449
450 static int opt_handler(int opt, int opt_index)
451 {
452         switch (opt) {
453         case 'v':
454                 verbose = true;
455                 break;
456         default:
457                 assert(0);
458         }
459
460         return 0;
461 }
462
463 /* Mod of igt_subtest_init that adds our extra options */
464 static void subtest_init(int argc, char **argv)
465 {
466         struct option long_opts[] = {
467                 {"verbose", 0, 0, 'v'}
468         };
469         const char *help_str = "  -v, --verbose";
470         int ret;
471
472         ret = igt_subtest_init_parse_opts(argc, argv, "v", long_opts,
473                                           help_str, opt_handler);
474
475         if (ret < 0)
476                 /* exit with no error for -h/--help */
477                 exit(ret == -1 ? 0 : ret);
478 }
479
480 int main(int argc, char **argv)
481 {
482         subtest_init(argc, argv);
483
484         igt_skip_on_simulation();
485
486         igt_fixture {
487                 const int device = drm_get_card();
488                 struct junk *junk = stuff;
489                 int ret;
490
491                 /* Use drm_open_any to verify device existence */
492                 drm_fd = drm_open_any();
493
494                 do {
495                         int val = -1;
496                         char *path;
497                         ret = asprintf(&path, sysfs_base_path, device, junk->name);
498                         igt_assert(ret != -1);
499                         junk->filp = fopen(path, junk->mode);
500                         igt_require(junk->filp);
501                         setbuf(junk->filp, NULL);
502
503                         val = readval(junk->filp);
504                         igt_assert(val >= 0);
505                         junk++;
506                 } while(junk->name != NULL);
507
508                 read_freqs(origfreqs);
509
510                 igt_install_exit_handler(pm_rps_exit_handler);
511
512                 load_helper_init();
513
514                 igt_debugfs_init(&dfs);
515         }
516
517         igt_subtest("basic-api")
518                 min_max_config(basic_check);
519
520         igt_subtest("min-max-config-idle")
521                 min_max_config(idle_check);
522
523         igt_subtest("min-max-config-loaded") {
524                 load_helper_run();
525                 min_max_config(loaded_check);
526                 load_helper_stop();
527         }
528
529         igt_exit();
530 }