uvtool.c

(plain)

    1 /* Copyright (c) 2024 Amelia Zabardast Ziabari
    2 **
    3 ** Redistribution and use in source and binary forms, with or without
    4 ** modification, are permitted provided that the following conditions are met:
    5 **
    6 **  1. Redistributions of source code must retain the above copyright notice,
    7 **     this list of conditions and the following disclaimer.
    8 **  2. Redistributions in binary form must reproduce the above copyright
    9 **     notice, this list of conditions and the following disclaimer in the
   10 **     documentation and/or other materials provided with the distribution.
   11 **
   12 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   13 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   14 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   15 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   16 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   17 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   18 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   19 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   20 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   21 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   22 ** POSSIBILITY OF SUCH DAMAGE.
   23 */
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #include <math.h>
   27 #include <string.h>
   28 
   29 #define ERROR(...) (fprintf(stderr, __VA_ARGS__),exit(1))
   30 
   31 static int states;
   32 struct state {
   33     int mV;
   34     int msr;
   35     };
   36 static struct state *table;
   37 
   38 
   39 static void validate_value( int v )
   40     {
   41     if ( ( v - 700 ) % 16 != 0 )
   42         ERROR("specified voltage value (%d) cannot compute to MSR value\n",v);
   43     }
   44 
   45 
   46 static void validate_range( int mi, int ma )
   47     {
   48     /* TODO: Pentium M always goes down to 700 mV, but unsure if any processors
   49     ** exceed 1500 mV.  someone should check this if they need it.
   50     ** (Core/Core 2 just have their minimum voltage locked?)
   51     */
   52     if ( mi < 700 || ma < 700 || mi > 1500 || ma > 1500 )
   53         ERROR("specified voltage invalid or out of sane range (700-1500)?\n");
   54     if ( mi > ma )
   55         ERROR("specified minimum voltage is larger than maximum voltage?\n");
   56     validate_value( mi );
   57     validate_value( ma );
   58     }
   59 
   60 
   61 static float lerp( float mi, float ma, float omi, float oma )
   62     {
   63     return mi + ( ma - mi ) * ( omi / oma );
   64     }
   65 
   66 
   67 static void gen_range( int mi, int ma )
   68     {
   69     int i;
   70     float mV;
   71 
   72     for ( i = 0; i < states; i++ )
   73         {
   74         mV = lerp( mi, ma, i, states - 1 );
   75         /* intel appears to round for default values, but some may prefer
   76         ** rounding up for safety reasons.  alternatively, just raise max mV
   77         */
   78         mV = roundf( ( mV - 700 ) / 16 );
   79         table[i].msr = (int)  mV;
   80         table[i].mV  = (int) (mV * 16) + 700;
   81         }
   82     }
   83 
   84 
   85 static void print_acc( )
   86     {
   87     static int t = 0;
   88 
   89     if ( (t++) >= 5 )
   90         {
   91         t = 0;
   92         printf( "\n" );
   93         }
   94     }
   95 
   96 
   97 static void print_range( int fmt )
   98     {
   99     int i;
  100 
  101     switch ( fmt )
  102         {
  103         case 2: /* vids only */
  104         for ( i = states - 1; i >= 0; i-- )
  105             printf( "%d ", table[i].msr );
  106         break;
  107 
  108         case 1: /* netbsd sysctl */
  109         printf( "machdep.cpu.voltage.custom=" );
  110 
  111         for ( i = states - 1; i >= 0; i-- )
  112             printf( "%d ", table[i].mV );
  113         break;
  114 
  115         default: /* human readable form */
  116         for ( i = 0; i < states; i++ )
  117             {
  118             printf( "%4d mV (%2d) ", table[i].mV, table[i].msr );
  119             print_acc( );
  120             }
  121         break;
  122         }
  123 
  124     printf( "\n" );
  125     }
  126 
  127 
  128 static void print_omap( int imi, int ima )
  129     {
  130     /* get the full range of possible vids so the user can select them */
  131     int i, msrmi, msrma;
  132 
  133     msrmi = (imi - 700) >> 4;
  134     msrma = (ima - 700) >> 4;
  135 
  136     for ( i = msrmi; i < (msrma + 1); i++ )
  137         {
  138         printf( "%4d mV (%2d) ", (i << 4) + 700, i );
  139         print_acc( );
  140         }
  141 
  142     printf( "\n" );
  143     }
  144 
  145 
  146 static void print_rmap( int imi, int ima, int fmt )
  147     {
  148     gen_range( imi, ima );
  149     print_range( fmt );
  150     }
  151 
  152 
  153 static void command( char *cmd, int imi, int ima )
  154     {
  155     char c;
  156 
  157     validate_range( imi, ima );
  158 
  159     if ( strlen(cmd) != 1 )
  160         {
  161         invalid:
  162         ERROR("invalid command (must be d, a, A, v)\n");
  163         }
  164     c = cmd[0];
  165 
  166     switch (c)
  167         {
  168         case 'd': print_omap( imi, ima );    break;
  169         case 'a': print_rmap( imi, ima, 0 ); break;
  170         case 'A': print_rmap( imi, ima, 1 ); break;
  171         case 'v': print_rmap( imi, ima, 2 ); break;
  172         default : goto invalid;
  173         }
  174     }
  175 
  176 int main( int argc, char **argv )
  177     {
  178     if (argc >= 2)
  179         {
  180         states = atoi(argv[1]);
  181         if ( states < 2 || states > 16 )
  182             ERROR("specified amount of states outside sane range (2-16)\n");
  183         table = malloc( sizeof(struct state) * states );
  184         }
  185     switch ( argc )
  186         {
  187         case 5: command( argv[2], atoi( argv[3] ), atoi( argv[4] ) ); break;
  188 
  189         default:
  190         ERROR(
  191             "insufficient params.\n"
  192             "%s <S> <M> <A> <B>: show possible VIDs\n"
  193             "where A-B is min voltage to max voltage in mV (e.g. 1020-1404)\n"
  194             "and M is a single-char operation:\n"
  195             "  d[umb] - print all possible MSR values in given range\n"
  196             "  a[uto] - auto-calculate new VID table for given range\n"
  197             "  A[uto] - ditto, but format as a NetBSD est.c sysctl\n"
  198             "  v[ids] - ditto, but just print raw VID numbers\n"
  199             "and S is the total number of original MSR states (e.g. 8)\n"
  200             "example: %s 8 a 1020 1404\n",
  201             argv[0], argv[0]);
  202         }
  203     return 0;
  204     }