162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Implementation of get_cpuid(). 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 2014, 2018 662306a36Sopenharmony_ci * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 762306a36Sopenharmony_ci * Thomas Richter <tmricht@linux.vnet.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <sys/types.h> 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci#include <unistd.h> 1362306a36Sopenharmony_ci#include <stdio.h> 1462306a36Sopenharmony_ci#include <string.h> 1562306a36Sopenharmony_ci#include <linux/ctype.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/zalloc.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "../../util/header.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define SYSINFO_MANU "Manufacturer:" 2262306a36Sopenharmony_ci#define SYSINFO_TYPE "Type:" 2362306a36Sopenharmony_ci#define SYSINFO_MODEL "Model:" 2462306a36Sopenharmony_ci#define SRVLVL_CPUMF "CPU-MF:" 2562306a36Sopenharmony_ci#define SRVLVL_VERSION "version=" 2662306a36Sopenharmony_ci#define SRVLVL_AUTHORIZATION "authorization=" 2762306a36Sopenharmony_ci#define SYSINFO "/proc/sysinfo" 2862306a36Sopenharmony_ci#define SRVLVL "/proc/service_levels" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciint get_cpuid(char *buffer, size_t sz) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci char *cp, *line = NULL, *line2; 3362306a36Sopenharmony_ci char type[8], model[33], version[8], manufacturer[32], authorization[8]; 3462306a36Sopenharmony_ci int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0; 3562306a36Sopenharmony_ci int read; 3662306a36Sopenharmony_ci unsigned long line_sz; 3762306a36Sopenharmony_ci size_t nbytes; 3862306a36Sopenharmony_ci FILE *sysinfo; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * Scan /proc/sysinfo line by line and read out values for 4262306a36Sopenharmony_ci * Manufacturer:, Type: and Model:, for example: 4362306a36Sopenharmony_ci * Manufacturer: IBM 4462306a36Sopenharmony_ci * Type: 2964 4562306a36Sopenharmony_ci * Model: 702 N96 4662306a36Sopenharmony_ci * The first word is the Model Capacity and the second word is 4762306a36Sopenharmony_ci * Model (can be omitted). Both words have a maximum size of 16 4862306a36Sopenharmony_ci * bytes. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci memset(manufacturer, 0, sizeof(manufacturer)); 5162306a36Sopenharmony_ci memset(type, 0, sizeof(type)); 5262306a36Sopenharmony_ci memset(model, 0, sizeof(model)); 5362306a36Sopenharmony_ci memset(version, 0, sizeof(version)); 5462306a36Sopenharmony_ci memset(authorization, 0, sizeof(authorization)); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci sysinfo = fopen(SYSINFO, "r"); 5762306a36Sopenharmony_ci if (sysinfo == NULL) 5862306a36Sopenharmony_ci return errno; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 6162306a36Sopenharmony_ci if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) { 6262306a36Sopenharmony_ci line2 = line + strlen(SYSINFO_MANU); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci while ((cp = strtok_r(line2, "\n ", &line2))) { 6562306a36Sopenharmony_ci mfsize += scnprintf(manufacturer + mfsize, 6662306a36Sopenharmony_ci sizeof(manufacturer) - mfsize, "%s", cp); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) { 7162306a36Sopenharmony_ci line2 = line + strlen(SYSINFO_TYPE); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci while ((cp = strtok_r(line2, "\n ", &line2))) { 7462306a36Sopenharmony_ci tpsize += scnprintf(type + tpsize, 7562306a36Sopenharmony_ci sizeof(type) - tpsize, "%s", cp); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) { 8062306a36Sopenharmony_ci line2 = line + strlen(SYSINFO_MODEL); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci while ((cp = strtok_r(line2, "\n ", &line2))) { 8362306a36Sopenharmony_ci mdsize += scnprintf(model + mdsize, sizeof(model) - mdsize, 8462306a36Sopenharmony_ci "%s%s", model[0] ? "," : "", cp); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci fclose(sysinfo); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Missing manufacturer, type or model information should not happen */ 9262306a36Sopenharmony_ci if (!manufacturer[0] || !type[0] || !model[0]) 9362306a36Sopenharmony_ci return EINVAL; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * Scan /proc/service_levels and return the CPU-MF counter facility 9762306a36Sopenharmony_ci * version number and authorization level. 9862306a36Sopenharmony_ci * Optional, does not exist on z/VM guests. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci sysinfo = fopen(SRVLVL, "r"); 10162306a36Sopenharmony_ci if (sysinfo == NULL) 10262306a36Sopenharmony_ci goto skip_sysinfo; 10362306a36Sopenharmony_ci while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 10462306a36Sopenharmony_ci if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF))) 10562306a36Sopenharmony_ci continue; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci line2 = line + strlen(SRVLVL_CPUMF); 10862306a36Sopenharmony_ci while ((cp = strtok_r(line2, "\n ", &line2))) { 10962306a36Sopenharmony_ci if (!strncmp(cp, SRVLVL_VERSION, 11062306a36Sopenharmony_ci strlen(SRVLVL_VERSION))) { 11162306a36Sopenharmony_ci char *sep = strchr(cp, '='); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci vssize += scnprintf(version + vssize, 11462306a36Sopenharmony_ci sizeof(version) - vssize, "%s", sep + 1); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci if (!strncmp(cp, SRVLVL_AUTHORIZATION, 11762306a36Sopenharmony_ci strlen(SRVLVL_AUTHORIZATION))) { 11862306a36Sopenharmony_ci char *sep = strchr(cp, '='); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci atsize += scnprintf(authorization + atsize, 12162306a36Sopenharmony_ci sizeof(authorization) - atsize, "%s", sep + 1); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci fclose(sysinfo); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ciskip_sysinfo: 12862306a36Sopenharmony_ci free(line); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (version[0] && authorization[0] ) 13162306a36Sopenharmony_ci nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s", 13262306a36Sopenharmony_ci manufacturer, type, model, version, 13362306a36Sopenharmony_ci authorization); 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type, 13662306a36Sopenharmony_ci model); 13762306a36Sopenharmony_ci return (nbytes >= sz) ? ENOBUFS : 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cichar *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci char *buf = malloc(128); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (buf && get_cpuid(buf, 128)) 14562306a36Sopenharmony_ci zfree(&buf); 14662306a36Sopenharmony_ci return buf; 14762306a36Sopenharmony_ci} 148