]>
Commit | Line | Data |
---|---|---|
55766568 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f8d9ccde AY |
2 | /* |
3 | * Implementation of get_cpuid(). | |
4 | * | |
eca0fa28 | 5 | * Copyright IBM Corp. 2014, 2018 |
f8d9ccde | 6 | * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> |
eca0fa28 | 7 | * Thomas Richter <tmricht@linux.vnet.ibm.com> |
f8d9ccde AY |
8 | */ |
9 | ||
10 | #include <sys/types.h> | |
11 | #include <unistd.h> | |
12 | #include <stdio.h> | |
13 | #include <string.h> | |
eca0fa28 | 14 | #include <ctype.h> |
f8d9ccde AY |
15 | |
16 | #include "../../util/header.h" | |
eca0fa28 TR |
17 | #include "../../util/util.h" |
18 | ||
19 | #define SYSINFO_MANU "Manufacturer:" | |
20 | #define SYSINFO_TYPE "Type:" | |
21 | #define SYSINFO_MODEL "Model:" | |
22 | #define SRVLVL_CPUMF "CPU-MF:" | |
23 | #define SRVLVL_VERSION "version=" | |
24 | #define SRVLVL_AUTHORIZATION "authorization=" | |
25 | #define SYSINFO "/proc/sysinfo" | |
26 | #define SRVLVL "/proc/service_levels" | |
f8d9ccde AY |
27 | |
28 | int get_cpuid(char *buffer, size_t sz) | |
29 | { | |
eca0fa28 TR |
30 | char *cp, *line = NULL, *line2; |
31 | char type[8], model[33], version[8], manufacturer[32], authorization[8]; | |
32 | int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0; | |
33 | int read; | |
34 | unsigned long line_sz; | |
35 | size_t nbytes; | |
36 | FILE *sysinfo; | |
37 | ||
38 | /* | |
39 | * Scan /proc/sysinfo line by line and read out values for | |
40 | * Manufacturer:, Type: and Model:, for example: | |
41 | * Manufacturer: IBM | |
42 | * Type: 2964 | |
43 | * Model: 702 N96 | |
44 | * The first word is the Model Capacity and the second word is | |
45 | * Model (can be omitted). Both words have a maximum size of 16 | |
46 | * bytes. | |
47 | */ | |
48 | memset(manufacturer, 0, sizeof(manufacturer)); | |
49 | memset(type, 0, sizeof(type)); | |
50 | memset(model, 0, sizeof(model)); | |
51 | memset(version, 0, sizeof(version)); | |
52 | memset(authorization, 0, sizeof(authorization)); | |
53 | ||
54 | sysinfo = fopen(SYSINFO, "r"); | |
55 | if (sysinfo == NULL) | |
56 | return -1; | |
57 | ||
58 | while ((read = getline(&line, &line_sz, sysinfo)) != -1) { | |
59 | if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) { | |
60 | line2 = line + strlen(SYSINFO_MANU); | |
61 | ||
62 | while ((cp = strtok_r(line2, "\n ", &line2))) { | |
63 | mfsize += scnprintf(manufacturer + mfsize, | |
64 | sizeof(manufacturer) - mfsize, "%s", cp); | |
65 | } | |
66 | } | |
67 | ||
68 | if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) { | |
69 | line2 = line + strlen(SYSINFO_TYPE); | |
70 | ||
71 | while ((cp = strtok_r(line2, "\n ", &line2))) { | |
72 | tpsize += scnprintf(type + tpsize, | |
73 | sizeof(type) - tpsize, "%s", cp); | |
74 | } | |
75 | } | |
76 | ||
77 | if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) { | |
78 | line2 = line + strlen(SYSINFO_MODEL); | |
79 | ||
80 | while ((cp = strtok_r(line2, "\n ", &line2))) { | |
47812e00 | 81 | mdsize += scnprintf(model + mdsize, sizeof(model) - mdsize, |
eca0fa28 TR |
82 | "%s%s", model[0] ? "," : "", cp); |
83 | } | |
84 | break; | |
85 | } | |
86 | } | |
87 | fclose(sysinfo); | |
f8d9ccde | 88 | |
eca0fa28 TR |
89 | /* Missing manufacturer, type or model information should not happen */ |
90 | if (!manufacturer[0] || !type[0] || !model[0]) | |
f8d9ccde AY |
91 | return -1; |
92 | ||
eca0fa28 TR |
93 | /* |
94 | * Scan /proc/service_levels and return the CPU-MF counter facility | |
95 | * version number and authorization level. | |
96 | * Optional, does not exist on z/VM guests. | |
97 | */ | |
98 | sysinfo = fopen(SRVLVL, "r"); | |
99 | if (sysinfo == NULL) | |
100 | goto skip_sysinfo; | |
101 | while ((read = getline(&line, &line_sz, sysinfo)) != -1) { | |
102 | if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF))) | |
103 | continue; | |
104 | ||
105 | line2 = line + strlen(SRVLVL_CPUMF); | |
106 | while ((cp = strtok_r(line2, "\n ", &line2))) { | |
107 | if (!strncmp(cp, SRVLVL_VERSION, | |
108 | strlen(SRVLVL_VERSION))) { | |
109 | char *sep = strchr(cp, '='); | |
110 | ||
111 | vssize += scnprintf(version + vssize, | |
112 | sizeof(version) - vssize, "%s", sep + 1); | |
113 | } | |
114 | if (!strncmp(cp, SRVLVL_AUTHORIZATION, | |
115 | strlen(SRVLVL_AUTHORIZATION))) { | |
116 | char *sep = strchr(cp, '='); | |
117 | ||
118 | atsize += scnprintf(authorization + atsize, | |
119 | sizeof(authorization) - atsize, "%s", sep + 1); | |
120 | } | |
121 | } | |
122 | } | |
123 | fclose(sysinfo); | |
124 | ||
125 | skip_sysinfo: | |
126 | free(line); | |
127 | ||
128 | if (version[0] && authorization[0] ) | |
129 | nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s", | |
130 | manufacturer, type, model, version, | |
131 | authorization); | |
132 | else | |
133 | nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type, | |
134 | model); | |
135 | return (nbytes >= sz) ? -1 : 0; | |
136 | } | |
137 | ||
138 | char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) | |
139 | { | |
140 | char *buf = malloc(128); | |
141 | ||
142 | if (buf && get_cpuid(buf, 128) < 0) | |
143 | zfree(&buf); | |
144 | return buf; | |
f8d9ccde | 145 | } |