1
0

amdgpu_asic_id.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Copyright © 2017 Advanced Micro Devices, Inc.
  3. * All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a
  6. * copy of this software and associated documentation files (the "Software"),
  7. * to deal in the Software without restriction, including without limitation
  8. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. * and/or sell copies of the Software, and to permit persons to whom the
  10. * Software is furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  19. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  20. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  21. * OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. */
  24. // secure_getenv requires _GNU_SOURCE
  25. #ifndef _GNU_SOURCE
  26. #define _GNU_SOURCE
  27. #endif
  28. #include <ctype.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <stdint.h>
  32. #include <string.h>
  33. #include <unistd.h>
  34. #include <errno.h>
  35. #include "xf86drm.h"
  36. #include "amdgpu_drm.h"
  37. #include "amdgpu_internal.h"
  38. static int parse_one_line(struct amdgpu_device *dev, const char *line)
  39. {
  40. char *buf, *saveptr;
  41. char *s_did;
  42. uint32_t did;
  43. char *s_rid;
  44. uint32_t rid;
  45. char *s_name;
  46. char *endptr;
  47. int r = -EINVAL;
  48. /* ignore empty line and commented line */
  49. if (strlen(line) == 0 || line[0] == '#')
  50. return -EAGAIN;
  51. buf = strdup(line);
  52. if (!buf)
  53. return -ENOMEM;
  54. /* device id */
  55. s_did = strtok_r(buf, ",", &saveptr);
  56. if (!s_did)
  57. goto out;
  58. did = strtol(s_did, &endptr, 16);
  59. if (*endptr)
  60. goto out;
  61. if (did != dev->info.asic_id) {
  62. r = -EAGAIN;
  63. goto out;
  64. }
  65. /* revision id */
  66. s_rid = strtok_r(NULL, ",", &saveptr);
  67. if (!s_rid)
  68. goto out;
  69. rid = strtol(s_rid, &endptr, 16);
  70. if (*endptr)
  71. goto out;
  72. if (rid != dev->info.pci_rev_id) {
  73. r = -EAGAIN;
  74. goto out;
  75. }
  76. /* marketing name */
  77. s_name = strtok_r(NULL, ",", &saveptr);
  78. if (!s_name)
  79. goto out;
  80. /* trim leading whitespaces or tabs */
  81. while (isblank(*s_name))
  82. s_name++;
  83. if (strlen(s_name) == 0)
  84. goto out;
  85. dev->marketing_name = strdup(s_name);
  86. if (dev->marketing_name)
  87. r = 0;
  88. else
  89. r = -ENOMEM;
  90. out:
  91. free(buf);
  92. return r;
  93. }
  94. static void amdgpu_parse_proc_cpuinfo(struct amdgpu_device *dev)
  95. {
  96. const char *search_key = "model name";
  97. const char *radeon_key = "Radeon";
  98. char *line = NULL;
  99. size_t len = 0;
  100. FILE *fp;
  101. fp = fopen("/proc/cpuinfo", "r");
  102. if (fp == NULL) {
  103. fprintf(stderr, "%s\n", strerror(errno));
  104. return;
  105. }
  106. while (getline(&line, &len, fp) != -1) {
  107. char *saveptr;
  108. char *value;
  109. if (strncmp(line, search_key, strlen(search_key)))
  110. continue;
  111. /* check for parts that have both CPU and GPU information */
  112. value = strstr(line, radeon_key);
  113. /* get content after the first colon */
  114. if (value == NULL) {
  115. value = strstr(line, ":");
  116. if (value == NULL)
  117. continue;
  118. value++;
  119. }
  120. /* strip whitespace */
  121. while (*value == ' ' || *value == '\t')
  122. value++;
  123. saveptr = strchr(value, '\n');
  124. if (saveptr)
  125. *saveptr = '\0';
  126. /* Add AMD to the new string if it's missing from slicing/dicing */
  127. if (strncmp(value, "AMD", 3) != 0) {
  128. char *tmp = malloc(strlen(value) + 5);
  129. if (!tmp)
  130. break;
  131. sprintf(tmp, "AMD %s", value);
  132. dev->marketing_name = tmp;
  133. } else
  134. dev->marketing_name = strdup(value);
  135. break;
  136. }
  137. free(line);
  138. fclose(fp);
  139. }
  140. #if HAVE_SECURE_GETENV
  141. static char *join_path(const char *dir, const char *file) {
  142. size_t dir_len = strlen(dir);
  143. size_t file_len = strlen(file);
  144. char *full_path = NULL;
  145. int need_slash = ((dir_len > 0) && (dir[dir_len - 1] != '/'));
  146. size_t total_len = dir_len + (need_slash ? 1 : 0) + file_len + 1; // +1 for null terminator
  147. if (dir_len == 0) {
  148. return strdup(file);
  149. }
  150. full_path = malloc(total_len);
  151. if (!full_path) {
  152. return NULL; // Memory allocation failed
  153. }
  154. strcpy(full_path, dir);
  155. if (need_slash) {
  156. full_path[dir_len] = '/';
  157. dir_len++;
  158. }
  159. strcpy(full_path + dir_len, file);
  160. return full_path;
  161. }
  162. static char **split_env_var(const char *env_var_content)
  163. {
  164. char **ret = NULL;
  165. char *dup_env_val;
  166. int elements = 1;
  167. int index = 1;
  168. if (!env_var_content || env_var_content[0] == '\0')
  169. return NULL;
  170. for(char *p = (char *)env_var_content; *p; p++) {
  171. if (*p == ':')
  172. elements++;
  173. }
  174. dup_env_val = strdup(env_var_content);
  175. if (!dup_env_val) {
  176. return NULL;
  177. }
  178. ret = malloc(sizeof(char *) * (elements + 1));
  179. if (!ret) {
  180. free(dup_env_val);
  181. return NULL;
  182. }
  183. ret[0] = dup_env_val;
  184. for(char *p = (char *)dup_env_val; *p; p++) {
  185. if (*p == ':') {
  186. *p = 0;
  187. ret[index++] = p + 1;
  188. }
  189. }
  190. ret[index] = NULL; // ensure that the last element in the array is NULL
  191. return ret;
  192. }
  193. static void split_env_var_free(char **split_var)
  194. {
  195. if (split_var) {
  196. // remember that the first element also points to the whole duplicated string,
  197. // which was modified in place by replacing ':' with '\0' characters
  198. free(split_var[0]);
  199. free(split_var);
  200. }
  201. }
  202. static char *find_asic_id_table(void)
  203. {
  204. // first check the paths in AMDGPU_ASIC_ID_TABLE_PATHS environment variable
  205. const char *amdgpu_asic_id_table_paths = secure_getenv("AMDGPU_ASIC_ID_TABLE_PATHS");
  206. const char *file_name = NULL;
  207. char *found_path = NULL;
  208. char **paths = NULL;
  209. if (!amdgpu_asic_id_table_paths)
  210. return NULL;
  211. // extract the file name from AMDGPU_ASIC_ID_TABLE
  212. file_name = strrchr(AMDGPU_ASIC_ID_TABLE, '/');
  213. if (!file_name)
  214. return NULL;
  215. file_name++; // skip the '/'
  216. paths = split_env_var(amdgpu_asic_id_table_paths);
  217. if (!paths)
  218. return NULL;
  219. // for each path, join with file_name and check if it exists
  220. for (int i = 0; paths[i] != NULL; i++) {
  221. char *full_path = join_path(paths[i], file_name);
  222. if (!full_path) {
  223. continue;
  224. }
  225. if (access(full_path, R_OK) == 0) {
  226. found_path = full_path;
  227. break;
  228. }
  229. }
  230. split_env_var_free(paths);
  231. return found_path;
  232. }
  233. #endif
  234. void amdgpu_parse_asic_ids(struct amdgpu_device *dev)
  235. {
  236. FILE *fp;
  237. char *line = NULL;
  238. size_t len = 0;
  239. ssize_t n;
  240. int line_num = 1;
  241. int r = 0;
  242. char *amdgpu_asic_id_table_path = NULL;
  243. #if HAVE_SECURE_GETENV
  244. // if this system lacks secure_getenv(), don't allow extra paths
  245. // for security reasons.
  246. amdgpu_asic_id_table_path = find_asic_id_table();
  247. #endif
  248. // if not found, use the default AMDGPU_ASIC_ID_TABLE path
  249. if (!amdgpu_asic_id_table_path)
  250. amdgpu_asic_id_table_path = strdup(AMDGPU_ASIC_ID_TABLE);
  251. fp = fopen(amdgpu_asic_id_table_path, "r");
  252. if (!fp) {
  253. fprintf(stderr, "%s: %s\n", amdgpu_asic_id_table_path,
  254. strerror(errno));
  255. goto get_cpu;
  256. }
  257. /* 1st valid line is file version */
  258. while ((n = getline(&line, &len, fp)) != -1) {
  259. /* trim trailing newline */
  260. if (line[n - 1] == '\n')
  261. line[n - 1] = '\0';
  262. /* ignore empty line and commented line */
  263. if (strlen(line) == 0 || line[0] == '#') {
  264. line_num++;
  265. continue;
  266. }
  267. drmMsg("%s version: %s\n", amdgpu_asic_id_table_path, line);
  268. break;
  269. }
  270. while ((n = getline(&line, &len, fp)) != -1) {
  271. /* trim trailing newline */
  272. if (line[n - 1] == '\n')
  273. line[n - 1] = '\0';
  274. r = parse_one_line(dev, line);
  275. if (r != -EAGAIN)
  276. break;
  277. line_num++;
  278. }
  279. if (r == -EINVAL) {
  280. fprintf(stderr, "Invalid format: %s: line %d: %s\n",
  281. amdgpu_asic_id_table_path, line_num, line);
  282. } else if (r && r != -EAGAIN) {
  283. fprintf(stderr, "%s: Cannot parse ASIC IDs: %s\n",
  284. __func__, strerror(-r));
  285. }
  286. free(line);
  287. fclose(fp);
  288. get_cpu:
  289. free(amdgpu_asic_id_table_path);
  290. if (dev->info.ids_flags & AMDGPU_IDS_FLAGS_FUSION &&
  291. dev->marketing_name == NULL) {
  292. amdgpu_parse_proc_cpuinfo(dev);
  293. }
  294. }