Replace libpci with new parser.

libpci was only used to find a marketing string for a device.
This patch looks for a pci.ids on disk and parses it to extract the
same string, using 'Device xxxx' as the fallback on file i/o error
or missing data from the text file. Tested by checking every vendor/
device pair against the values returned from libpci.

Change-Id: I21af3157472c1824d57fcee31393c6ee8ce07330
Signed-off-by: Jon Chesterfield <Jonathan.Chesterfield@amd.com>


[ROCm/ROCR-Runtime commit: 0a1718b753]
Этот коммит содержится в:
Jon Chesterfield
2020-03-19 01:04:28 +00:00
родитель c90e8c1389
Коммит ffadc0c8c6
7 изменённых файлов: 373 добавлений и 26 удалений
+6 -7
Просмотреть файл
@@ -105,6 +105,7 @@ set ( HSAKMT_SRC "src/debug.c"
"src/libhsakmt.c"
"src/memory.c"
"src/openclose.c"
"src/pci_ids.c"
"src/perfctr.c"
"src/pmc_table.c"
"src/queues.c"
@@ -127,10 +128,8 @@ set_property ( TARGET ${HSAKMT_TARGET} PROPERTY VERSION "${LIB_VERSION_STRING}"
set_property ( TARGET ${HSAKMT_TARGET} PROPERTY SOVERSION "${LIB_VERSION_MAJOR}" )
find_package(PkgConfig)
pkg_check_modules(PC_LIBPCI REQUIRED libpci)
include_directories ( ${PC_LIBPCI_INCLUDEDIR} )
target_link_libraries ( ${HSAKMT_TARGET}
pthread rt numa ${PC_LIBPCI_LIBRARIES}
pthread rt numa
)
## Define default variable and variables for the optional build target hsakmt-dev
@@ -195,15 +194,15 @@ endif()
# Debian package specific variables
set ( CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/RadeonOpenCompute/ROCT-Thunk-Interface" )
set ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/DEBIAN/postinst;${CMAKE_CURRENT_SOURCE_DIR}/DEBIAN/prerm" )
set ( CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libnuma1, libpci3, zlib1g, libudev1" )
set ( CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libnuma1, zlib1g, libudev1" )
# RPM package specific variables
if( DISTRO_ID MATCHES "sles" )
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, libnuma-devel, pciutils, libgcc_s1")
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, libnuma-devel, libgcc_s1")
elseif( DISTRO_ID MATCHES "centos" AND DISTRO_RELEASE MATCHES "6" )
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, numactl, pciutils-libs, libgcc" )
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, numactl, libgcc" )
else()
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, numactl-libs, pciutils-libs, libgcc" )
set ( CPACK_RPM_PACKAGE_REQUIRES "glibc, numactl-libs, libgcc" )
endif()
set ( CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/RPM/rpm_post" )
set ( CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/RPM/rpm_postun" )
+4 -5
Просмотреть файл
@@ -36,7 +36,7 @@
#include <sys/mman.h>
#include <sys/time.h>
#include <errno.h>
#include <pci/pci.h>
#include <numa.h>
#include <numaif.h>
#include "rbtree.h"
@@ -2119,7 +2119,7 @@ HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes)
HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS;
char *disableCache, *pagedUserptr, *checkUserptr, *guardPagesStr, *reserveSvm;
unsigned int guardPages = 1;
struct pci_access *pacc;
struct pci_ids pacc;
uint64_t svm_base = 0, svm_limit = 0;
uint32_t svm_alignment = 0;
@@ -2166,8 +2166,7 @@ HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes)
* gets called before hsaKmtAcquireSystemProperties() is called.
*/
pacc = pci_alloc();
pci_init(pacc);
pacc = pci_ids_create();
for (i = 0; i < NumNodes; i++) {
memset(&props, 0, sizeof(props));
ret = topology_sysfs_get_node_props(i, &props, &gpu_id, pacc);
@@ -2204,7 +2203,7 @@ HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes)
gpu_mem_count++;
}
}
pci_cleanup(pacc);
pci_ids_destroy(pacc);
/* The ioctl will also return Number of Nodes if
* args.kfd_process_device_apertures_ptr is set to NULL. This is not
+2 -2
Просмотреть файл
@@ -27,10 +27,10 @@
#define LIBHSAKMT_H_INCLUDED
#include "hsakmt.h"
#include "pci_ids.h"
#include <pthread.h>
#include <stdint.h>
#include <limits.h>
#include <pci/pci.h>
extern int kfd_fd;
extern unsigned long kfd_open_count;
@@ -155,7 +155,7 @@ HSAKMT_STATUS validate_nodeid_array(uint32_t **gpu_id_array,
uint32_t NumberOfNodes, uint32_t *NodeArray);
HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id, HsaNodeProperties *props,
uint32_t *gpu_id, struct pci_access* pacc);
uint32_t *gpu_id, struct pci_ids pacc);
HSAKMT_STATUS topology_sysfs_get_system_props(HsaSystemProperties *props);
bool topology_is_dgpu(uint16_t device_id);
bool topology_is_svm_needed(uint16_t device_id);
+304
Просмотреть файл
@@ -0,0 +1,304 @@
/*
* Copyright © 2020 Advanced Micro Devices, Inc.
*
* 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 (including
* the next paragraph) 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 AUTHORS OR COPYRIGHT
* HOLDERS 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.
*/
/*
* Parse a pci.ids text file to extract 'device_name'
* # Vendors, devices and subsystems. Please keep sorted.
* # Syntax:
* # vendor vendor_name
* # device device_name <-- single tab
* # subvendor subdevice subsystem_name <-- two tabs
*/
/*
* Example section of file. Searching for 1002/130c
*
* 1002 Advanced Micro Devices, Inc. [AMD/ATI]
* # fields elided
* 130a Kaveri [Radeon R6 Graphics]
* 130b Kaveri [Radeon R4 Graphics]
*
* 130c Kaveri [Radeon R7 Graphics] <- result
* # ^-------------------------^
*
* 130d Kaveri [Radeon R6 Graphics]
* 130e Kaveri [Radeon R5 Graphics]
* # fields elided
* # next vendor region starts
* 1003 ULSI Systems
* 0201 US201
*/
#define _GNU_SOURCE
#include <string.h>
#include "pci_ids.h"
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
static const char *const pci_ids_paths[] = {
"/usr/share/hwdata/pci.ids", // update-pciids
"/usr/share/misc/pci.ids", // debian
"/usr/share/pci.ids", // redhat
"/var/lib/pciutils/pci.ids", // also debian
"pci.ids",
};
static struct pci_ids pci_ids_create_from_file(const char *path)
{
struct pci_ids failure = {
.fd = -1,
};
int fd = open(path, O_RDONLY, 0);
if (fd == -1)
return failure;
struct stat sb;
fstat(fd, &sb);
size_t sz = sb.st_size;
if (sz == 0) {
close(fd);
return failure;
}
sz = (sz < UINT32_MAX) ? sz : UINT32_MAX;
void *addr = mmap(0, sz, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) {
close(fd);
return failure;
}
return (struct pci_ids){
.fd = fd,
.addr = addr,
.size = sz,
};
}
struct pci_ids pci_ids_create(void)
{
size_t sz = sizeof(pci_ids_paths) / sizeof(pci_ids_paths[0]);
for (size_t i = 0; i < sz; i++) {
struct pci_ids res = pci_ids_create_from_file(pci_ids_paths[i]);
if (res.fd != -1)
return res;
}
return (struct pci_ids){ .fd = -1 };
}
void pci_ids_destroy(struct pci_ids f)
{
if (f.fd != -1) {
munmap(f.addr, f.size);
close(f.fd);
}
}
struct range {
// Iterator pair, start <= end. Can dereference [start end)
unsigned char *start;
unsigned char *end;
};
static bool empty_range(struct range r)
{
return r.start == r.end;
}
static void write_as_hex(uint16_t x, char *b)
{
static const char digits[] = "0123456789abcdef";
for (unsigned int i = 0; i < 4; i++) {
unsigned int index = 0xf & (x >> 4 * (3 - i));
b[i] = digits[index];
}
}
static struct range find_vendor(struct range r, uint16_t VendorId)
{
if (empty_range(r))
return r;
char needle[5] = { '\n' };
write_as_hex(VendorId, &needle[1]);
unsigned char *s =
memmem(r.start, r.end - r.start, needle, sizeof(needle));
if (s) {
r.start = s;
} else {
r.start = r.end;
assert(empty_range(r));
}
return r;
}
static struct range trim_whitespace(struct range r)
{
while (!empty_range(r) && isspace(r.start[0]))
r.start++;
while (!empty_range(r) && isspace(r.end[-1]))
r.end--;
return r;
}
static struct range skip_vendor_id(struct range r)
{
const struct range failure = { 0, 0 };
assert(!empty_range(r));
// Expect an initial newline to skip over
if (r.start[0] != '\n')
return failure;
r.start++;
if (empty_range(r))
return failure;
// Skip rest of line
r.start = memchr(r.start, '\n', r.end - r.start);
if (!r.start)
return failure;
return r;
}
static struct range find_device(struct range r, uint16_t DeviceId)
{
struct range failure = { 0, 0 };
if (empty_range(r))
return failure;
r = skip_vendor_id(r);
if (empty_range(r))
return failure;
assert(r.start[0] == '\n');
char needle[6] = { '\n', '\t' };
write_as_hex(DeviceId, &needle[2]);
for (;;) {
size_t width = r.end - r.start;
if (width < sizeof(needle))
return failure;
unsigned char *line_end = memchr(r.start + 1, '\n', width - 1);
if (!line_end) {
// File may not end with a newline
line_end = r.end;
}
if (memcmp(r.start, needle, sizeof(needle)) == 0) {
// Success
r.start += sizeof(needle);
r.end = line_end;
return trim_whitespace(r);
}
if (isxdigit(r.start[1])) {
// Reached the end of this region
return failure;
}
// Otherwise ignore whatever is on the line, e.g. '#'
r.start = line_end;
}
}
static void copy_range_to_buffer(struct range r, char *buf, size_t size)
{
assert(!empty_range(r));
size_t to_copy = (r.end - r.start);
to_copy = to_copy < (size - 1) ? to_copy : size - 1;
memcpy(buf, r.start, to_copy);
buf[to_copy] = '\0';
}
static void write_fallback_to_buffer(char *buf, size_t size, uint16_t DeviceId)
{
char tmp[] = "Device xxxx";
static_assert(sizeof(tmp) == 12, "");
write_as_hex(DeviceId, &tmp[7]);
size_t to_copy = (sizeof(tmp) <= size) ? sizeof(tmp) : size;
memcpy(buf, tmp, to_copy);
buf[size - 1] = '\0';
}
char *pci_ids_lookup(struct pci_ids f, char *buf, size_t size,
uint16_t VendorId, uint16_t DeviceId)
{
if (f.fd == -1) {
write_fallback_to_buffer(buf, size, DeviceId);
return buf;
}
struct range whole_file = {
.start = f.addr,
.end = (unsigned char *)f.addr + f.size,
};
struct range vendor = find_vendor(whole_file, VendorId);
struct range device = find_device(vendor, DeviceId);
if (!empty_range(device))
copy_range_to_buffer(device, buf, size);
else
write_fallback_to_buffer(buf, size, DeviceId);
return buf;
}
+46
Просмотреть файл
@@ -0,0 +1,46 @@
/*
* Copyright © 2020 Advanced Micro Devices, Inc.
*
* 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 (including
* the next paragraph) 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 AUTHORS OR COPYRIGHT
* HOLDERS 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.
*/
#ifndef SRC_PCI_IDS_H_
#define SRC_PCI_IDS_H_
#include <stddef.h>
#include <stdint.h>
struct pci_ids {
int32_t fd; // -1 if file access failed
uint32_t size;
void *addr;
};
// Sixteen byte struct is passed in registers. Avoids calling malloc/free.
struct pci_ids pci_ids_create(void);
void pci_ids_destroy(struct pci_ids pacc);
// Writes to buf. Returns buf. Does not fail.
char *pci_ids_lookup(struct pci_ids pacc, char *buf, size_t buf_size,
uint16_t VendorId, uint16_t DeviceId);
#endif // SRC_PCI_IDS_H_
+4 -4
Просмотреть файл
@@ -77,11 +77,11 @@ struct perf_shared_table {
struct perf_counts_values {
union {
struct {
u64 val;
u64 ena;
u64 run;
uint64_t val;
uint64_t ena;
uint64_t run;
};
u64 values[3];
uint64_t values[3];
};
};
+7 -8
Просмотреть файл
@@ -31,7 +31,7 @@
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <pci/pci.h>
#include <errno.h>
#include <sys/sysinfo.h>
@@ -910,7 +910,7 @@ exit:
HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id,
HsaNodeProperties *props,
uint32_t *gpu_id,
struct pci_access *pacc)
struct pci_ids pacc)
{
FILE *fd;
char *read_buf, *p, *envvar, dummy;
@@ -1068,7 +1068,7 @@ HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id,
* Retrieve the marketing name of the node using pcilib,
* convert UTF8 to UTF16
*/
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE,
name = pci_ids_lookup(pacc, namebuf, sizeof(namebuf),
props->VendorId, props->DeviceId);
for (i = 0; name[i] != 0 && i < HSA_PUBLIC_NAME_SIZE - 1; i++)
props->MarketingName[i] = name[i];
@@ -1731,7 +1731,7 @@ HSAKMT_STATUS topology_take_snapshot(void)
HsaSystemProperties sys_props;
node_props_t *temp_props = 0;
HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS;
struct pci_access *pacc;
struct pci_ids pacc;
struct proc_cpuinfo *cpuinfo;
const uint32_t num_procs = get_nprocs();
@@ -1755,8 +1755,7 @@ retry:
ret = HSAKMT_STATUS_NO_MEMORY;
goto err;
}
pacc = pci_alloc();
pci_init(pacc);
pacc = pci_ids_create();
for (i = 0; i < sys_props.NumNodes; i++) {
ret = topology_sysfs_get_node_props(i,
&temp_props[i].node,
@@ -1826,7 +1825,7 @@ retry:
* remote node (node_to) is not accessible
*/
while (sys_link_id < temp_props[i].node.NumIOLinks &&
link_id < sys_props.NumNodes - 1) {
link_id < sys_props.NumNodes - 1) {
ret = topology_sysfs_get_iolink_props(i, sys_link_id++,
&temp_props[i].link[link_id]);
if (ret == HSAKMT_STATUS_NOT_SUPPORTED) {
@@ -1842,7 +1841,7 @@ retry:
temp_props[i].node.NumIOLinks = link_id;
}
}
pci_cleanup(pacc);
pci_ids_destroy(pacc);
}
/* All direct IO links are created in the kernel. Here we need to