1f8d9ccdeSAlexander Yarygin /* 2f8d9ccdeSAlexander Yarygin * Implementation of get_cpuid(). 3f8d9ccdeSAlexander Yarygin * 4eca0fa28SThomas Richter * Copyright IBM Corp. 2014, 2018 5f8d9ccdeSAlexander Yarygin * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 6eca0fa28SThomas Richter * Thomas Richter <tmricht@linux.vnet.ibm.com> 7f8d9ccdeSAlexander Yarygin * 8f8d9ccdeSAlexander Yarygin * This program is free software; you can redistribute it and/or modify 9f8d9ccdeSAlexander Yarygin * it under the terms of the GNU General Public License (version 2 only) 10f8d9ccdeSAlexander Yarygin * as published by the Free Software Foundation. 11f8d9ccdeSAlexander Yarygin */ 12f8d9ccdeSAlexander Yarygin 13f8d9ccdeSAlexander Yarygin #include <sys/types.h> 14f8d9ccdeSAlexander Yarygin #include <unistd.h> 15f8d9ccdeSAlexander Yarygin #include <stdio.h> 16f8d9ccdeSAlexander Yarygin #include <string.h> 17eca0fa28SThomas Richter #include <ctype.h> 18f8d9ccdeSAlexander Yarygin 19f8d9ccdeSAlexander Yarygin #include "../../util/header.h" 20eca0fa28SThomas Richter #include "../../util/util.h" 21eca0fa28SThomas Richter 22eca0fa28SThomas Richter #define SYSINFO_MANU "Manufacturer:" 23eca0fa28SThomas Richter #define SYSINFO_TYPE "Type:" 24eca0fa28SThomas Richter #define SYSINFO_MODEL "Model:" 25eca0fa28SThomas Richter #define SRVLVL_CPUMF "CPU-MF:" 26eca0fa28SThomas Richter #define SRVLVL_VERSION "version=" 27eca0fa28SThomas Richter #define SRVLVL_AUTHORIZATION "authorization=" 28eca0fa28SThomas Richter #define SYSINFO "/proc/sysinfo" 29eca0fa28SThomas Richter #define SRVLVL "/proc/service_levels" 30f8d9ccdeSAlexander Yarygin 31f8d9ccdeSAlexander Yarygin int get_cpuid(char *buffer, size_t sz) 32f8d9ccdeSAlexander Yarygin { 33eca0fa28SThomas Richter char *cp, *line = NULL, *line2; 34eca0fa28SThomas Richter char type[8], model[33], version[8], manufacturer[32], authorization[8]; 35eca0fa28SThomas Richter int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0; 36eca0fa28SThomas Richter int read; 37eca0fa28SThomas Richter unsigned long line_sz; 38eca0fa28SThomas Richter size_t nbytes; 39eca0fa28SThomas Richter FILE *sysinfo; 40f8d9ccdeSAlexander Yarygin 41eca0fa28SThomas Richter /* 42eca0fa28SThomas Richter * Scan /proc/sysinfo line by line and read out values for 43eca0fa28SThomas Richter * Manufacturer:, Type: and Model:, for example: 44eca0fa28SThomas Richter * Manufacturer: IBM 45eca0fa28SThomas Richter * Type: 2964 46eca0fa28SThomas Richter * Model: 702 N96 47eca0fa28SThomas Richter * The first word is the Model Capacity and the second word is 48eca0fa28SThomas Richter * Model (can be omitted). Both words have a maximum size of 16 49eca0fa28SThomas Richter * bytes. 50eca0fa28SThomas Richter */ 51eca0fa28SThomas Richter memset(manufacturer, 0, sizeof(manufacturer)); 52eca0fa28SThomas Richter memset(type, 0, sizeof(type)); 53eca0fa28SThomas Richter memset(model, 0, sizeof(model)); 54eca0fa28SThomas Richter memset(version, 0, sizeof(version)); 55eca0fa28SThomas Richter memset(authorization, 0, sizeof(authorization)); 56eca0fa28SThomas Richter 57eca0fa28SThomas Richter sysinfo = fopen(SYSINFO, "r"); 58eca0fa28SThomas Richter if (sysinfo == NULL) 59f8d9ccdeSAlexander Yarygin return -1; 60f8d9ccdeSAlexander Yarygin 61eca0fa28SThomas Richter while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 62eca0fa28SThomas Richter if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) { 63eca0fa28SThomas Richter line2 = line + strlen(SYSINFO_MANU); 64eca0fa28SThomas Richter 65eca0fa28SThomas Richter while ((cp = strtok_r(line2, "\n ", &line2))) { 66eca0fa28SThomas Richter mfsize += scnprintf(manufacturer + mfsize, 67eca0fa28SThomas Richter sizeof(manufacturer) - mfsize, "%s", cp); 68eca0fa28SThomas Richter } 69eca0fa28SThomas Richter } 70eca0fa28SThomas Richter 71eca0fa28SThomas Richter if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) { 72eca0fa28SThomas Richter line2 = line + strlen(SYSINFO_TYPE); 73eca0fa28SThomas Richter 74eca0fa28SThomas Richter while ((cp = strtok_r(line2, "\n ", &line2))) { 75eca0fa28SThomas Richter tpsize += scnprintf(type + tpsize, 76eca0fa28SThomas Richter sizeof(type) - tpsize, "%s", cp); 77eca0fa28SThomas Richter } 78eca0fa28SThomas Richter } 79eca0fa28SThomas Richter 80eca0fa28SThomas Richter if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) { 81eca0fa28SThomas Richter line2 = line + strlen(SYSINFO_MODEL); 82eca0fa28SThomas Richter 83eca0fa28SThomas Richter while ((cp = strtok_r(line2, "\n ", &line2))) { 8447812e00SThomas Richter mdsize += scnprintf(model + mdsize, sizeof(model) - mdsize, 85eca0fa28SThomas Richter "%s%s", model[0] ? "," : "", cp); 86eca0fa28SThomas Richter } 87eca0fa28SThomas Richter break; 88eca0fa28SThomas Richter } 89eca0fa28SThomas Richter } 90eca0fa28SThomas Richter fclose(sysinfo); 91eca0fa28SThomas Richter 92eca0fa28SThomas Richter /* Missing manufacturer, type or model information should not happen */ 93eca0fa28SThomas Richter if (!manufacturer[0] || !type[0] || !model[0]) 94eca0fa28SThomas Richter return -1; 95eca0fa28SThomas Richter 96eca0fa28SThomas Richter /* 97eca0fa28SThomas Richter * Scan /proc/service_levels and return the CPU-MF counter facility 98eca0fa28SThomas Richter * version number and authorization level. 99eca0fa28SThomas Richter * Optional, does not exist on z/VM guests. 100eca0fa28SThomas Richter */ 101eca0fa28SThomas Richter sysinfo = fopen(SRVLVL, "r"); 102eca0fa28SThomas Richter if (sysinfo == NULL) 103eca0fa28SThomas Richter goto skip_sysinfo; 104eca0fa28SThomas Richter while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 105eca0fa28SThomas Richter if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF))) 106eca0fa28SThomas Richter continue; 107eca0fa28SThomas Richter 108eca0fa28SThomas Richter line2 = line + strlen(SRVLVL_CPUMF); 109eca0fa28SThomas Richter while ((cp = strtok_r(line2, "\n ", &line2))) { 110eca0fa28SThomas Richter if (!strncmp(cp, SRVLVL_VERSION, 111eca0fa28SThomas Richter strlen(SRVLVL_VERSION))) { 112eca0fa28SThomas Richter char *sep = strchr(cp, '='); 113eca0fa28SThomas Richter 114eca0fa28SThomas Richter vssize += scnprintf(version + vssize, 115eca0fa28SThomas Richter sizeof(version) - vssize, "%s", sep + 1); 116eca0fa28SThomas Richter } 117eca0fa28SThomas Richter if (!strncmp(cp, SRVLVL_AUTHORIZATION, 118eca0fa28SThomas Richter strlen(SRVLVL_AUTHORIZATION))) { 119eca0fa28SThomas Richter char *sep = strchr(cp, '='); 120eca0fa28SThomas Richter 121eca0fa28SThomas Richter atsize += scnprintf(authorization + atsize, 122eca0fa28SThomas Richter sizeof(authorization) - atsize, "%s", sep + 1); 123eca0fa28SThomas Richter } 124eca0fa28SThomas Richter } 125eca0fa28SThomas Richter } 126eca0fa28SThomas Richter fclose(sysinfo); 127eca0fa28SThomas Richter 128eca0fa28SThomas Richter skip_sysinfo: 129eca0fa28SThomas Richter free(line); 130eca0fa28SThomas Richter 131eca0fa28SThomas Richter if (version[0] && authorization[0] ) 132eca0fa28SThomas Richter nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s", 133eca0fa28SThomas Richter manufacturer, type, model, version, 134eca0fa28SThomas Richter authorization); 135eca0fa28SThomas Richter else 136eca0fa28SThomas Richter nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type, 137eca0fa28SThomas Richter model); 138eca0fa28SThomas Richter return (nbytes >= sz) ? -1 : 0; 139eca0fa28SThomas Richter } 140eca0fa28SThomas Richter 141eca0fa28SThomas Richter char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 142eca0fa28SThomas Richter { 143eca0fa28SThomas Richter char *buf = malloc(128); 144eca0fa28SThomas Richter 145eca0fa28SThomas Richter if (buf && get_cpuid(buf, 128) < 0) 146eca0fa28SThomas Richter zfree(&buf); 147eca0fa28SThomas Richter return buf; 148f8d9ccdeSAlexander Yarygin } 1494cb7d3ecSThomas Richter 1504cb7d3ecSThomas Richter /* 1514cb7d3ecSThomas Richter * Compare the cpuid string returned by get_cpuid() function 1524cb7d3ecSThomas Richter * with the name generated by the jevents file read from 1534cb7d3ecSThomas Richter * pmu-events/arch/s390/mapfile.csv. 1544cb7d3ecSThomas Richter * 1554cb7d3ecSThomas Richter * Parameter mapcpuid is the cpuid as stored in the 1564cb7d3ecSThomas Richter * pmu-events/arch/s390/mapfile.csv. This is just the type number. 1574cb7d3ecSThomas Richter * Parameter cpuid is the cpuid returned by function get_cpuid(). 1584cb7d3ecSThomas Richter */ 1594cb7d3ecSThomas Richter int strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) 1604cb7d3ecSThomas Richter { 1614cb7d3ecSThomas Richter char *cp = strchr(cpuid, ','); 1624cb7d3ecSThomas Richter 1634cb7d3ecSThomas Richter if (cp == NULL) 1644cb7d3ecSThomas Richter return -1; 1654cb7d3ecSThomas Richter return strncmp(cp + 1, mapcpuid, strlen(mapcpuid)); 1664cb7d3ecSThomas Richter } 167