Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 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 | * |
| 26 | */ |
| 27 | |
| 28 | #define _GNU_SOURCE |
| 29 | #include <stdio.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <string.h> |
| 32 | #include <unistd.h> |
| 33 | #include "drmtest.h" |
| 34 | |
| 35 | static bool verbose = false; |
| 36 | static int origmin, origmax; |
| 37 | |
| 38 | #define restore_assert(COND) do { \ |
| 39 | if (!(COND)) { \ |
| 40 | writeval(stuff[MIN].filp, origmin); \ |
| 41 | writeval(stuff[MAX].filp, origmax); \ |
| 42 | assert(0); \ |
| 43 | } \ |
| 44 | } while (0); |
| 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 | }; |
| 55 | |
| 56 | struct junk { |
| 57 | const char *name; |
| 58 | const char *mode; |
| 59 | FILE *filp; |
| 60 | } stuff[] = { |
| 61 | { "cur", "r", NULL }, { "min", "rb+", NULL }, { "max", "rb+", NULL }, { "RP0", "r", NULL }, { "RP1", "r", NULL }, { "RPn", "r", NULL }, { NULL, NULL, NULL } |
| 62 | }; |
| 63 | |
| 64 | static int readval(FILE *filp) |
| 65 | { |
| 66 | int val; |
Imre Deak | 3a622b9 | 2012-10-10 16:04:42 +0300 | [diff] [blame] | 67 | int scanned; |
| 68 | |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 69 | fflush(filp); |
| 70 | rewind(filp); |
Imre Deak | 3a622b9 | 2012-10-10 16:04:42 +0300 | [diff] [blame] | 71 | scanned = fscanf(filp, "%d", &val); |
| 72 | assert(scanned == 1); |
| 73 | |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 74 | return val; |
| 75 | } |
| 76 | |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 77 | static int do_writeval(FILE *filp, int val, int lerrno) |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 78 | { |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 79 | /* Must write twice to sysfs since the first one simply calculates the size and won't return the error */ |
| 80 | int ret; |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 81 | rewind(filp); |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 82 | ret = fprintf(filp, "%d", val); |
| 83 | rewind(filp); |
| 84 | ret = fprintf(filp, "%d", val); |
| 85 | if (ret && lerrno) |
| 86 | assert(errno = lerrno); |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 87 | fflush(filp); |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 88 | return ret; |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 89 | } |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 90 | #define writeval(filp, val) do_writeval(filp, val, 0) |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 91 | |
| 92 | #define fcur (readval(stuff[CUR].filp)) |
| 93 | #define fmin (readval(stuff[MIN].filp)) |
| 94 | #define fmax (readval(stuff[MAX].filp)) |
| 95 | #define frp0 (readval(stuff[RP0].filp)) |
| 96 | #define frp1 (readval(stuff[RP1].filp)) |
| 97 | #define frpn (readval(stuff[RPn].filp)) |
| 98 | |
| 99 | static void setfreq(int val) |
| 100 | { |
| 101 | writeval(stuff[MIN].filp, val); |
| 102 | writeval(stuff[MAX].filp, val); |
| 103 | } |
| 104 | |
| 105 | static void checkit(void) |
| 106 | { |
| 107 | restore_assert(fmin <= fmax); |
| 108 | restore_assert(fcur <= fmax); |
| 109 | restore_assert(fmin <= fcur); |
| 110 | restore_assert(frpn <= fmin); |
| 111 | restore_assert(fmax <= frp0); |
| 112 | restore_assert(frp1 <= frp0); |
| 113 | restore_assert(frpn <= frp1); |
| 114 | restore_assert(frp0 != 0); |
| 115 | restore_assert(frp1 != 0); |
| 116 | } |
| 117 | |
| 118 | static void dumpit(void) |
| 119 | { |
| 120 | struct junk *junk = stuff; |
| 121 | do { |
| 122 | printf("gt frequency %s (MHz): %d\n", junk->name, readval(junk->filp)); |
| 123 | junk++; |
| 124 | } while(junk->name != NULL); |
| 125 | |
| 126 | printf("\n"); |
| 127 | } |
| 128 | |
| 129 | |
| 130 | int main(int argc, char *argv[]) |
| 131 | { |
| 132 | const int device = drm_get_card(0); |
| 133 | struct junk *junk = stuff; |
| 134 | int fd, ret; |
| 135 | |
| 136 | if (argc > 1) |
| 137 | verbose++; |
| 138 | |
| 139 | /* Use drm_open_any to verify device existence */ |
| 140 | fd = drm_open_any(); |
| 141 | close(fd); |
| 142 | |
| 143 | do { |
| 144 | int val = -1; |
| 145 | char *path; |
| 146 | ret = asprintf(&path, sysfs_base_path, device, junk->name); |
| 147 | assert(ret != -1); |
| 148 | junk->filp = fopen(path, junk->mode); |
| 149 | if (junk->filp == NULL) { |
Daniel Vetter | 021909e | 2012-11-27 20:04:15 +0100 | [diff] [blame] | 150 | printf("Kernel is too old. GTFO\n"); |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 151 | exit(77); |
| 152 | } |
| 153 | val = readval(junk->filp); |
| 154 | assert(val >= 0); |
| 155 | junk++; |
| 156 | } while(junk->name != NULL); |
| 157 | |
| 158 | origmin = fmin; |
| 159 | origmax = fmax; |
| 160 | |
| 161 | if (verbose) |
| 162 | printf("Original min = %d\nOriginal max = %d\n", origmin, origmax); |
| 163 | |
| 164 | if (verbose) |
| 165 | dumpit(); |
| 166 | |
| 167 | checkit(); |
| 168 | setfreq(fmin); |
| 169 | if (verbose) |
| 170 | dumpit(); |
| 171 | restore_assert(fcur == fmin); |
| 172 | setfreq(fmax); |
| 173 | if (verbose) |
| 174 | dumpit(); |
| 175 | restore_assert(fcur == fmax); |
| 176 | checkit(); |
| 177 | |
| 178 | /* And some errors */ |
| 179 | writeval(stuff[MIN].filp, frpn - 1); |
| 180 | writeval(stuff[MAX].filp, frp0 + 1000); |
| 181 | checkit(); |
| 182 | |
| 183 | writeval(stuff[MIN].filp, fmax + 1000); |
| 184 | writeval(stuff[MAX].filp, fmin - 1); |
| 185 | checkit(); |
| 186 | |
Ben Widawsky | dc3ac00 | 2012-10-15 10:05:56 -0700 | [diff] [blame] | 187 | do_writeval(stuff[MIN].filp, 0x11111110, EINVAL); |
| 188 | do_writeval(stuff[MAX].filp, 0, EINVAL); |
| 189 | |
Ben Widawsky | 0cedccc | 2012-09-07 18:12:07 -0700 | [diff] [blame] | 190 | writeval(stuff[MIN].filp, origmin); |
| 191 | writeval(stuff[MAX].filp, origmax); |
| 192 | |
| 193 | exit(EXIT_SUCCESS); |
| 194 | } |