diff --git a/projects/rocr-runtime/CMakeLists.txt b/projects/rocr-runtime/CMakeLists.txt index 077ab51c36..2e117ddf87 100644 --- a/projects/rocr-runtime/CMakeLists.txt +++ b/projects/rocr-runtime/CMakeLists.txt @@ -122,6 +122,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" @@ -154,6 +155,7 @@ 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(LIBDRM REQUIRED libdrm) # get OS-info for OS-specific build dependencies get_os_info() @@ -164,29 +166,11 @@ find_library(NUMA NAMES libnuma.so REQUIRED) message(STATUS "LIBC:" ${LIBC}) message(STATUS "NUMA:" ${NUMA}) -## If environment variable DRM_DIR is set, the script -## will pick up the corresponding libraries from that path. -if( DEFINED ENV{DRM_DIR} ) -#assume header files and libraries are under the same path - set ( DRM_DIR $ENV{DRM_DIR} ) - set ( DRM_INCLUDE_DIRS ${DRM_DIR}/include ) - link_directories(${DRM_DIR}/lib64) - set ( DRM_LIBRARIES drm ) - set ( DRM_AMDGPU_LIBRARIES drm_amdgpu ) -else() -# The module name passed to pkg_check_modules() is determined by the -# name of file *.pc - pkg_check_modules(DRM REQUIRED libdrm) - pkg_check_modules(DRM_AMDGPU REQUIRED libdrm_amdgpu) - include_directories(${DRM_AMDGPU_INCLUDE_DIRS}) -endif() -include_directories(${DRM_INCLUDE_DIRS}) - target_link_libraries ( ${HSAKMT_TARGET} - PRIVATE ${DRM_LDFLAGS} ${DRM_AMDGPU_LDFLAGS} pthread rt ${LIBC} ${NUMA} + PRIVATE pthread rt ${LIBC} ${NUMA} ) -target_compile_options(${HSAKMT_TARGET} PRIVATE ${DRM_CFLAGS} ${HSAKMT_C_FLAGS}) +target_compile_options(${HSAKMT_TARGET} PRIVATE ${LIBDRM_CFLAGS} ${HSAKMT_C_FLAGS}) if(NOT DISTRO_ID MATCHES "ubuntu") find_library(LIBGCC NAMES libgcc_s.so.1 REQUIRED) message(STATUS "LIBGCC:" ${LIBGCC}) @@ -349,10 +333,10 @@ set(PACKAGE_VERSION_STR "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_ set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION_STR}") # Setting devel package dependendent version -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libdrm-dev, rocm-core") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "rocm-core") set(CPACK_DEBIAN_PACKAGE_REPLACES "hsakmt-roct") -set(CPACK_RPM_PACKAGE_REQUIRES "libdrm-devel, rocm-core") +set(CPACK_RPM_PACKAGE_REQUIRES "rocm-core") # Set the names now using CPACK utility set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT") diff --git a/projects/rocr-runtime/src/fmm.c b/projects/rocr-runtime/src/fmm.c index 2657415246..02e044bb88 100644 --- a/projects/rocr-runtime/src/fmm.c +++ b/projects/rocr-runtime/src/fmm.c @@ -2150,6 +2150,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_ids pacc; uint64_t svm_base = 0, svm_limit = 0; uint32_t svm_alignment = 0; @@ -2196,11 +2197,13 @@ HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes) * gets called before hsaKmtAcquireSystemProperties() is called. */ + pacc = pci_ids_create(); + is_dgpu = false; for (i = 0; i < NumNodes; i++) { memset(&props, 0, sizeof(props)); - ret = topology_sysfs_get_node_props(i, &props, &gpu_id, NULL, NULL); + ret = topology_sysfs_get_node_props(i, &props, &gpu_id, pacc, NULL, NULL); if (ret != HSAKMT_STATUS_SUCCESS) goto sysfs_parse_failed; @@ -2237,6 +2240,8 @@ HSAKMT_STATUS fmm_init_process_apertures(unsigned int NumNodes) } } + 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 * required since Number of nodes is already known. Kernel will fill in diff --git a/projects/rocr-runtime/src/libhsakmt.h b/projects/rocr-runtime/src/libhsakmt.h index 9d4be20409..1232f80374 100644 --- a/projects/rocr-runtime/src/libhsakmt.h +++ b/projects/rocr-runtime/src/libhsakmt.h @@ -28,6 +28,7 @@ #include "linux/kfd_ioctl.h" #include "hsakmt.h" +#include "pci_ids.h" #include #include #include @@ -174,7 +175,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, + uint32_t *gpu_id, struct pci_ids pacc, bool *p2p_links, uint32_t *num_p2pLinks); HSAKMT_STATUS topology_sysfs_get_system_props(HsaSystemProperties *props); void topology_setup_is_dgpu_param(HsaNodeProperties *props); diff --git a/projects/rocr-runtime/src/pci_ids.c b/projects/rocr-runtime/src/pci_ids.c new file mode 100644 index 0000000000..0c8df69d28 --- /dev/null +++ b/projects/rocr-runtime/src/pci_ids.c @@ -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 + +#include "pci_ids.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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; +} diff --git a/projects/rocr-runtime/src/pci_ids.h b/projects/rocr-runtime/src/pci_ids.h new file mode 100644 index 0000000000..4c0d44c57e --- /dev/null +++ b/projects/rocr-runtime/src/pci_ids.h @@ -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 +#include + +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_ diff --git a/projects/rocr-runtime/src/topology.c b/projects/rocr-runtime/src/topology.c index 9ff33ba0f1..06f744153b 100644 --- a/projects/rocr-runtime/src/topology.c +++ b/projects/rocr-runtime/src/topology.c @@ -34,9 +34,6 @@ #include #include -#include -#include -#include #include "libhsakmt.h" #include "fmm.h" @@ -937,39 +934,10 @@ exit: return ret; } -static int topology_get_marketing_name(int minor, uint16_t *marketing_name) -{ - int drm_fd; - uint32_t major_version; - uint32_t minor_version; - amdgpu_device_handle device_handle; - const char *name; - int i; - - if (marketing_name == NULL) - return -1; - drm_fd = drmOpenRender(minor); - if (drm_fd < 0) - return -1; - if (amdgpu_device_initialize(drm_fd, - &major_version, &minor_version, &device_handle) < 0) { - drmClose(drm_fd); - return -1; - } - name = amdgpu_get_marketing_name(device_handle); - if (name != NULL) { - for (i = 0; name[i] != 0 && i < HSA_PUBLIC_NAME_SIZE - 1; i++) - marketing_name[i] = name[i]; - marketing_name[i] = '\0'; - } - amdgpu_device_deinitialize(device_handle); - drmClose(drm_fd); - return 0; -} - HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id, HsaNodeProperties *props, uint32_t *gpu_id, + struct pci_ids pacc, bool *p2p_links, uint32_t *num_p2pLinks) { @@ -978,9 +946,11 @@ HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id, char prop_name[256]; char path[256]; unsigned long long prop_val; - uint32_t prog, major, minor, step; + uint32_t i, prog, major, minor, step; int read_size; const struct hsa_gfxip_table *hsa_gfxip; + char namebuf[HSA_PUBLIC_NAME_SIZE]; + const char *name; uint32_t sys_node_id; uint32_t gfxv = 0; uint8_t gfxv_major, gfxv_minor, gfxv_stepping; @@ -1145,12 +1115,14 @@ HSAKMT_STATUS topology_sysfs_get_node_props(uint32_t node_id, if (!props->NumCPUCores) { /* Is dGPU Node, not APU - * Retrieve the marketing name of the node. + * Retrieve the marketing name of the node using pcilib, + * convert UTF8 to UTF16 */ - if (topology_get_marketing_name(props->DrmRenderMinor, - props->MarketingName) != 0) - pr_info("failed to get marketing name for device ID 0x%x\n", - props->DeviceId); + 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]; + props->MarketingName[i] = '\0'; } /* Get VGPR/SGPR size in byte per CU */ @@ -1819,6 +1791,7 @@ HSAKMT_STATUS topology_take_snapshot(void) HsaSystemProperties sys_props; node_props_t *temp_props = 0; HSAKMT_STATUS ret = HSAKMT_STATUS_SUCCESS; + struct pci_ids pacc; struct proc_cpuinfo *cpuinfo; const uint32_t num_procs = get_nprocs(); uint32_t num_ioLinks; @@ -1845,11 +1818,12 @@ retry: ret = HSAKMT_STATUS_NO_MEMORY; goto err; } + pacc = pci_ids_create(); for (i = 0; i < sys_props.NumNodes; i++) { ret = topology_sysfs_get_node_props(i, &temp_props[i].node, &temp_props[i].gpu_id, - &p2p_links, &num_p2pLinks); + pacc, &p2p_links, &num_p2pLinks); if (ret != HSAKMT_STATUS_SUCCESS) { free_properties(temp_props, i); goto err; @@ -1954,6 +1928,7 @@ retry: temp_props[i].node.NumIOLinks = link_id; } } + pci_ids_destroy(pacc); } if (!p2p_links) {