mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2026-05-31 04:28:20 +02:00
Since glibc-2.43:
For ISO C23, the functions bsearch, memchr, strchr, strpbrk, strrchr,
strstr, wcschr, wcspbrk, wcsrchr, wcsstr and wmemchr that return pointers
into their input arrays now have definitions as macros that return a
pointer to a const-qualified type when the input argument is a pointer
to a const-qualified type.
fixes:
amdgpu/amdgpu_asic_id.c: In function 'find_asic_id_table':
amdgpu/amdgpu_asic_id.c:249:19: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
249 | file_name = strrchr(AMDGPU_ASIC_ID_TABLE, '/');
| ^
Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
345 lines
7.7 KiB
C
345 lines
7.7 KiB
C
/*
|
|
* Copyright © 2017 Advanced Micro Devices, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
// secure_getenv requires _GNU_SOURCE
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "xf86drm.h"
|
|
#include "amdgpu_drm.h"
|
|
#include "amdgpu_internal.h"
|
|
|
|
static int parse_one_line(struct amdgpu_device *dev, const char *line)
|
|
{
|
|
char *buf, *saveptr;
|
|
char *s_did;
|
|
uint32_t did;
|
|
char *s_rid;
|
|
uint32_t rid;
|
|
char *s_name;
|
|
char *endptr;
|
|
int r = -EINVAL;
|
|
|
|
/* ignore empty line and commented line */
|
|
if (strlen(line) == 0 || line[0] == '#')
|
|
return -EAGAIN;
|
|
|
|
buf = strdup(line);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
/* device id */
|
|
s_did = strtok_r(buf, ",", &saveptr);
|
|
if (!s_did)
|
|
goto out;
|
|
|
|
did = strtol(s_did, &endptr, 16);
|
|
if (*endptr)
|
|
goto out;
|
|
|
|
if (did != dev->info.asic_id) {
|
|
r = -EAGAIN;
|
|
goto out;
|
|
}
|
|
|
|
/* revision id */
|
|
s_rid = strtok_r(NULL, ",", &saveptr);
|
|
if (!s_rid)
|
|
goto out;
|
|
|
|
rid = strtol(s_rid, &endptr, 16);
|
|
if (*endptr)
|
|
goto out;
|
|
|
|
if (rid != dev->info.pci_rev_id) {
|
|
r = -EAGAIN;
|
|
goto out;
|
|
}
|
|
|
|
/* marketing name */
|
|
s_name = strtok_r(NULL, ",", &saveptr);
|
|
if (!s_name)
|
|
goto out;
|
|
|
|
/* trim leading whitespaces or tabs */
|
|
while (isblank(*s_name))
|
|
s_name++;
|
|
if (strlen(s_name) == 0)
|
|
goto out;
|
|
|
|
dev->marketing_name = strdup(s_name);
|
|
if (dev->marketing_name)
|
|
r = 0;
|
|
else
|
|
r = -ENOMEM;
|
|
|
|
out:
|
|
free(buf);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void amdgpu_parse_proc_cpuinfo(struct amdgpu_device *dev)
|
|
{
|
|
const char *search_key = "model name";
|
|
const char *radeon_key = "Radeon";
|
|
char *line = NULL;
|
|
size_t len = 0;
|
|
FILE *fp;
|
|
|
|
fp = fopen("/proc/cpuinfo", "r");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "%s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
while (getline(&line, &len, fp) != -1) {
|
|
char *saveptr;
|
|
char *value;
|
|
|
|
if (strncmp(line, search_key, strlen(search_key)))
|
|
continue;
|
|
|
|
/* check for parts that have both CPU and GPU information */
|
|
value = strstr(line, radeon_key);
|
|
|
|
/* get content after the first colon */
|
|
if (value == NULL) {
|
|
value = strstr(line, ":");
|
|
if (value == NULL)
|
|
continue;
|
|
value++;
|
|
}
|
|
|
|
/* strip whitespace */
|
|
while (*value == ' ' || *value == '\t')
|
|
value++;
|
|
saveptr = strchr(value, '\n');
|
|
if (saveptr)
|
|
*saveptr = '\0';
|
|
|
|
/* Add AMD to the new string if it's missing from slicing/dicing */
|
|
if (strncmp(value, "AMD", 3) != 0) {
|
|
char *tmp = malloc(strlen(value) + 5);
|
|
|
|
if (!tmp)
|
|
break;
|
|
sprintf(tmp, "AMD %s", value);
|
|
dev->marketing_name = tmp;
|
|
} else
|
|
dev->marketing_name = strdup(value);
|
|
break;
|
|
}
|
|
|
|
free(line);
|
|
fclose(fp);
|
|
}
|
|
|
|
#if HAVE_SECURE_GETENV
|
|
static char *join_path(const char *dir, const char *file) {
|
|
size_t dir_len = strlen(dir);
|
|
size_t file_len = strlen(file);
|
|
char *full_path = NULL;
|
|
|
|
int need_slash = ((dir_len > 0) && (dir[dir_len - 1] != '/'));
|
|
size_t total_len = dir_len + (need_slash ? 1 : 0) + file_len + 1; // +1 for null terminator
|
|
|
|
if (dir_len == 0) {
|
|
return strdup(file);
|
|
}
|
|
|
|
full_path = malloc(total_len);
|
|
if (!full_path) {
|
|
return NULL; // Memory allocation failed
|
|
}
|
|
|
|
strcpy(full_path, dir);
|
|
if (need_slash) {
|
|
full_path[dir_len] = '/';
|
|
dir_len++;
|
|
}
|
|
strcpy(full_path + dir_len, file);
|
|
|
|
return full_path;
|
|
}
|
|
|
|
static char **split_env_var(const char *env_var_content)
|
|
{
|
|
char **ret = NULL;
|
|
char *dup_env_val;
|
|
int elements = 1;
|
|
int index = 1;
|
|
|
|
if (!env_var_content || env_var_content[0] == '\0')
|
|
return NULL;
|
|
|
|
for(char *p = (char *)env_var_content; *p; p++) {
|
|
if (*p == ':')
|
|
elements++;
|
|
}
|
|
|
|
dup_env_val = strdup(env_var_content);
|
|
if (!dup_env_val) {
|
|
return NULL;
|
|
}
|
|
ret = malloc(sizeof(char *) * (elements + 1));
|
|
ret[0] = dup_env_val;
|
|
for(char *p = (char *)dup_env_val; *p; p++) {
|
|
if (*p == ':') {
|
|
*p = 0;
|
|
ret[index++] = p + 1;
|
|
}
|
|
}
|
|
ret[index] = NULL; // ensure that the last element in the array is NULL
|
|
return ret;
|
|
}
|
|
|
|
static void split_env_var_free(char **split_var)
|
|
{
|
|
if (split_var) {
|
|
// remember that the first element also points to the whole duplicated string,
|
|
// which was modified in place by replacing ':' with '\0' characters
|
|
free(split_var[0]);
|
|
free(split_var);
|
|
}
|
|
}
|
|
|
|
static char *find_asic_id_table(void)
|
|
{
|
|
// first check the paths in AMDGPU_ASIC_ID_TABLE_PATHS environment variable
|
|
const char *amdgpu_asic_id_table_paths = secure_getenv("AMDGPU_ASIC_ID_TABLE_PATHS");
|
|
const char *file_name = NULL;
|
|
char *found_path = NULL;
|
|
char **paths = NULL;
|
|
|
|
if (!amdgpu_asic_id_table_paths)
|
|
return NULL;
|
|
|
|
// extract the file name from AMDGPU_ASIC_ID_TABLE
|
|
file_name = strrchr(AMDGPU_ASIC_ID_TABLE, '/');
|
|
if (!file_name)
|
|
return NULL;
|
|
file_name++; // skip the '/'
|
|
|
|
paths = split_env_var(amdgpu_asic_id_table_paths);
|
|
if (!paths)
|
|
return NULL;
|
|
|
|
// for each path, join with file_name and check if it exists
|
|
for (int i = 0; paths[i] != NULL; i++) {
|
|
char *full_path = join_path(paths[i], file_name);
|
|
if (!full_path) {
|
|
continue;
|
|
}
|
|
if (access(full_path, R_OK) == 0) {
|
|
found_path = full_path;
|
|
break;
|
|
}
|
|
}
|
|
split_env_var_free(paths);
|
|
return found_path;
|
|
}
|
|
#endif
|
|
|
|
void amdgpu_parse_asic_ids(struct amdgpu_device *dev)
|
|
{
|
|
FILE *fp;
|
|
char *line = NULL;
|
|
size_t len = 0;
|
|
ssize_t n;
|
|
int line_num = 1;
|
|
int r = 0;
|
|
|
|
char *amdgpu_asic_id_table_path = NULL;
|
|
#if HAVE_SECURE_GETENV
|
|
// if this system lacks secure_getenv(), don't allow extra paths
|
|
// for security reasons.
|
|
amdgpu_asic_id_table_path = find_asic_id_table();
|
|
#endif
|
|
// if not found, use the default AMDGPU_ASIC_ID_TABLE path
|
|
if (!amdgpu_asic_id_table_path)
|
|
amdgpu_asic_id_table_path = strdup(AMDGPU_ASIC_ID_TABLE);
|
|
|
|
fp = fopen(amdgpu_asic_id_table_path, "r");
|
|
if (!fp) {
|
|
fprintf(stderr, "%s: %s\n", amdgpu_asic_id_table_path,
|
|
strerror(errno));
|
|
goto get_cpu;
|
|
}
|
|
|
|
/* 1st valid line is file version */
|
|
while ((n = getline(&line, &len, fp)) != -1) {
|
|
/* trim trailing newline */
|
|
if (line[n - 1] == '\n')
|
|
line[n - 1] = '\0';
|
|
|
|
/* ignore empty line and commented line */
|
|
if (strlen(line) == 0 || line[0] == '#') {
|
|
line_num++;
|
|
continue;
|
|
}
|
|
|
|
drmMsg("%s version: %s\n", amdgpu_asic_id_table_path, line);
|
|
break;
|
|
}
|
|
|
|
while ((n = getline(&line, &len, fp)) != -1) {
|
|
/* trim trailing newline */
|
|
if (line[n - 1] == '\n')
|
|
line[n - 1] = '\0';
|
|
|
|
r = parse_one_line(dev, line);
|
|
if (r != -EAGAIN)
|
|
break;
|
|
|
|
line_num++;
|
|
}
|
|
|
|
if (r == -EINVAL) {
|
|
fprintf(stderr, "Invalid format: %s: line %d: %s\n",
|
|
amdgpu_asic_id_table_path, line_num, line);
|
|
} else if (r && r != -EAGAIN) {
|
|
fprintf(stderr, "%s: Cannot parse ASIC IDs: %s\n",
|
|
__func__, strerror(-r));
|
|
}
|
|
|
|
free(line);
|
|
fclose(fp);
|
|
|
|
get_cpu:
|
|
free(amdgpu_asic_id_table_path);
|
|
if (dev->info.ids_flags & AMDGPU_IDS_FLAGS_FUSION &&
|
|
dev->marketing_name == NULL) {
|
|
amdgpu_parse_proc_cpuinfo(dev);
|
|
}
|
|
}
|