linux/tools/power/cpupower/utils/helpers/amd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#if defined(__i386__) || defined(__x86_64__)
   3#include <unistd.h>
   4#include <errno.h>
   5#include <stdio.h>
   6#include <stdint.h>
   7
   8#include <pci/pci.h>
   9
  10#include "helpers/helpers.h"
  11
  12#define MSR_AMD_PSTATE_STATUS   0xc0010063
  13#define MSR_AMD_PSTATE          0xc0010064
  14#define MSR_AMD_PSTATE_LIMIT    0xc0010061
  15
  16union core_pstate {
  17        /* pre fam 17h: */
  18        struct {
  19                unsigned fid:6;
  20                unsigned did:3;
  21                unsigned vid:7;
  22                unsigned res1:6;
  23                unsigned nbdid:1;
  24                unsigned res2:2;
  25                unsigned nbvid:7;
  26                unsigned iddval:8;
  27                unsigned idddiv:2;
  28                unsigned res3:21;
  29                unsigned en:1;
  30        } pstate;
  31        /* since fam 17h: */
  32        struct {
  33                unsigned fid:8;
  34                unsigned did:6;
  35                unsigned vid:8;
  36                unsigned iddval:8;
  37                unsigned idddiv:2;
  38                unsigned res1:31;
  39                unsigned en:1;
  40        } pstatedef;
  41        unsigned long long val;
  42};
  43
  44static int get_did(union core_pstate pstate)
  45{
  46        int t;
  47
  48        if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF)
  49                t = pstate.pstatedef.did;
  50        else if (cpupower_cpu_info.family == 0x12)
  51                t = pstate.val & 0xf;
  52        else
  53                t = pstate.pstate.did;
  54
  55        return t;
  56}
  57
  58static int get_cof(union core_pstate pstate)
  59{
  60        int t;
  61        int fid, did, cof;
  62
  63        did = get_did(pstate);
  64        if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATEDEF) {
  65                fid = pstate.pstatedef.fid;
  66                cof = 200 * fid / did;
  67        } else {
  68                t = 0x10;
  69                fid = pstate.pstate.fid;
  70                if (cpupower_cpu_info.family == 0x11)
  71                        t = 0x8;
  72                cof = (100 * (fid + t)) >> did;
  73        }
  74        return cof;
  75}
  76
  77/* Needs:
  78 * cpu          -> the cpu that gets evaluated
  79 * boost_states -> how much boost states the machines support
  80 *
  81 * Fills up:
  82 * pstates -> a pointer to an array of size MAX_HW_PSTATES
  83 *            must be initialized with zeros.
  84 *            All available  HW pstates (including boost states)
  85 * no      -> amount of pstates above array got filled up with
  86 *
  87 * returns zero on success, -1 on failure
  88 */
  89int decode_pstates(unsigned int cpu, int boost_states,
  90                   unsigned long *pstates, int *no)
  91{
  92        int i, psmax;
  93        union core_pstate pstate;
  94        unsigned long long val;
  95
  96        /* Only read out frequencies from HW if HW Pstate is supported,
  97         * otherwise frequencies are exported via ACPI tables.
  98         */
  99        if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_HW_PSTATE))
 100                return -1;
 101
 102        if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
 103                return -1;
 104
 105        psmax = (val >> 4) & 0x7;
 106        psmax += boost_states;
 107        for (i = 0; i <= psmax; i++) {
 108                if (i >= MAX_HW_PSTATES) {
 109                        fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
 110                                psmax, MAX_HW_PSTATES);
 111                        return -1;
 112                }
 113                if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
 114                        return -1;
 115
 116                /* The enabled bit (bit 63) is common for all families */
 117                if (!pstate.pstatedef.en)
 118                        continue;
 119
 120                pstates[i] = get_cof(pstate);
 121        }
 122        *no = i;
 123        return 0;
 124}
 125
 126int amd_pci_get_num_boost_states(int *active, int *states)
 127{
 128        struct pci_access *pci_acc;
 129        struct pci_dev *device;
 130        uint8_t val = 0;
 131
 132        *active = *states = 0;
 133
 134        device = pci_slot_func_init(&pci_acc, 0x18, 4);
 135
 136        if (device == NULL)
 137                return -ENODEV;
 138
 139        val = pci_read_byte(device, 0x15c);
 140        if (val & 3)
 141                *active = 1;
 142        else
 143                *active = 0;
 144        *states = (val >> 2) & 7;
 145
 146        pci_cleanup(pci_acc);
 147        return 0;
 148}
 149#endif /* defined(__i386__) || defined(__x86_64__) */
 150