1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // dump_psb. (c) 2004, Dave Jones, Red Hat Inc. |
3 | |
4 | #include <fcntl.h> |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | #include <unistd.h> |
9 | |
10 | #define _GNU_SOURCE |
11 | #include <getopt.h> |
12 | |
13 | #include <sys/mman.h> |
14 | |
15 | #define LEN (0x100000 - 0xc0000) |
16 | #define OFFSET (0xc0000) |
17 | |
18 | #ifndef __packed |
19 | #define __packed __attribute((packed)) |
20 | #endif |
21 | |
22 | static long relevant; |
23 | |
24 | static const int fid_to_mult[32] = { |
25 | 110, 115, 120, 125, 50, 55, 60, 65, |
26 | 70, 75, 80, 85, 90, 95, 100, 105, |
27 | 30, 190, 40, 200, 130, 135, 140, 210, |
28 | 150, 225, 160, 165, 170, 180, -1, -1, |
29 | }; |
30 | |
31 | static const int vid_to_voltage[32] = { |
32 | 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, |
33 | 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, |
34 | 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, |
35 | 1075, 1050, 1024, 1000, 975, 950, 925, 0, |
36 | }; |
37 | |
38 | struct { |
39 | char [10]; |
40 | u_char ; |
41 | u_char ; |
42 | u_short ; |
43 | u_char ; |
44 | u_char ; |
45 | } __packed; |
46 | |
47 | struct { |
48 | u_int32_t ; |
49 | u_char ; |
50 | u_char ; |
51 | u_char ; |
52 | u_char ; |
53 | } __packed; |
54 | |
55 | static u_int fsb; |
56 | static u_int sgtc; |
57 | |
58 | static int |
59 | decode_pst(char *p, int npstates) |
60 | { |
61 | int i; |
62 | int freq, fid, vid; |
63 | |
64 | for (i = 0; i < npstates; ++i) { |
65 | fid = *p++; |
66 | vid = *p++; |
67 | freq = 100 * fid_to_mult[fid] * fsb; |
68 | |
69 | printf(" %2d %8dkHz FID %02x (%2d.%01d) VID %02x (%4dmV)\n" , |
70 | i, |
71 | freq, |
72 | fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, |
73 | vid, vid_to_voltage[vid]); |
74 | } |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | static |
80 | void decode_psb(char *p, int numpst) |
81 | { |
82 | int i; |
83 | struct psb_header *psb; |
84 | struct pst_header *pst; |
85 | |
86 | psb = (struct psb_header*) p; |
87 | |
88 | if (psb->version != 0x12) |
89 | return; |
90 | |
91 | printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n" , |
92 | psb->version, |
93 | psb->flags, |
94 | psb->settlingtime, |
95 | psb->res1, |
96 | psb->numpst); |
97 | sgtc = psb->settlingtime * 100; |
98 | |
99 | if (sgtc < 10000) |
100 | sgtc = 10000; |
101 | |
102 | p = ((char *) psb) + sizeof(struct psb_header); |
103 | |
104 | if (numpst < 0) |
105 | numpst = psb->numpst; |
106 | else |
107 | printf("Overriding number of pst :%d\n" , numpst); |
108 | |
109 | for (i = 0; i < numpst; i++) { |
110 | pst = (struct pst_header*) p; |
111 | |
112 | if (relevant != 0) { |
113 | if (relevant!= pst->cpuid) |
114 | goto next_one; |
115 | } |
116 | |
117 | printf(" PST %d cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n" , |
118 | i+1, |
119 | pst->cpuid, |
120 | pst->fsb, |
121 | pst->maxfid, |
122 | pst->startvid, |
123 | pst->numpstates); |
124 | |
125 | fsb = pst->fsb; |
126 | decode_pst(p: p + sizeof(struct pst_header), npstates: pst->numpstates); |
127 | |
128 | next_one: |
129 | p += sizeof(struct pst_header) + 2*pst->numpstates; |
130 | } |
131 | |
132 | } |
133 | |
134 | static struct option info_opts[] = { |
135 | {"numpst" , no_argument, NULL, 'n'}, |
136 | }; |
137 | |
138 | void print_help(void) |
139 | { |
140 | printf ("Usage: dump_psb [options]\n" ); |
141 | printf ("Options:\n" ); |
142 | printf (" -n, --numpst Set number of PST tables to scan\n" ); |
143 | printf (" -r, --relevant Only display PSTs relevant to cpuid N\n" ); |
144 | } |
145 | |
146 | int |
147 | main(int argc, char *argv[]) |
148 | { |
149 | int fd; |
150 | int numpst=-1; |
151 | int ret=0, cont=1; |
152 | char *mem = NULL; |
153 | char *p; |
154 | |
155 | do { |
156 | ret = getopt_long(argc, argv, "hr:n:" , info_opts, NULL); |
157 | switch (ret){ |
158 | case '?': |
159 | case 'h': |
160 | print_help(); |
161 | cont = 0; |
162 | break; |
163 | case 'r': |
164 | relevant = strtol(optarg, NULL, 16); |
165 | break; |
166 | case 'n': |
167 | numpst = strtol(optarg, NULL, 10); |
168 | break; |
169 | case -1: |
170 | cont = 0; |
171 | break; |
172 | } |
173 | |
174 | } while(cont); |
175 | |
176 | fd = open("/dev/mem" , O_RDONLY); |
177 | if (fd < 0) { |
178 | printf ("Couldn't open /dev/mem. Are you root?\n" ); |
179 | exit(1); |
180 | } |
181 | |
182 | mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); |
183 | close(fd); |
184 | |
185 | for (p = mem; p - mem < LEN; p+=16) { |
186 | if (memcmp(p, "AMDK7PNOW!" , 10) == 0) { |
187 | decode_psb(p, numpst); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | munmap(mem, LEN); |
193 | return 0; |
194 | } |
195 | |