18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/pci.h> 268c2ecf20Sopenharmony_ci#include <linux/errno.h> 278c2ecf20Sopenharmony_ci#include <linux/acpi.h> 288c2ecf20Sopenharmony_ci#include <linux/hash.h> 298c2ecf20Sopenharmony_ci#include <linux/cpufreq.h> 308c2ecf20Sopenharmony_ci#include <linux/log2.h> 318c2ecf20Sopenharmony_ci#include <linux/dmi.h> 328c2ecf20Sopenharmony_ci#include <linux/atomic.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "kfd_priv.h" 358c2ecf20Sopenharmony_ci#include "kfd_crat.h" 368c2ecf20Sopenharmony_ci#include "kfd_topology.h" 378c2ecf20Sopenharmony_ci#include "kfd_device_queue_manager.h" 388c2ecf20Sopenharmony_ci#include "kfd_iommu.h" 398c2ecf20Sopenharmony_ci#include "amdgpu_amdkfd.h" 408c2ecf20Sopenharmony_ci#include "amdgpu_ras.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* topology_device_list - Master list of all topology devices */ 438c2ecf20Sopenharmony_cistatic struct list_head topology_device_list; 448c2ecf20Sopenharmony_cistatic struct kfd_system_properties sys_props; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(topology_lock); 478c2ecf20Sopenharmony_cistatic atomic_t topology_crat_proximity_domain; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct kfd_topology_device *kfd_topology_device_by_proximity_domain( 508c2ecf20Sopenharmony_ci uint32_t proximity_domain) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev; 538c2ecf20Sopenharmony_ci struct kfd_topology_device *device = NULL; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci down_read(&topology_lock); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci list_for_each_entry(top_dev, &topology_device_list, list) 588c2ecf20Sopenharmony_ci if (top_dev->proximity_domain == proximity_domain) { 598c2ecf20Sopenharmony_ci device = top_dev; 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci up_read(&topology_lock); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return device; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct kfd_topology_device *kfd_topology_device_by_id(uint32_t gpu_id) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev = NULL; 718c2ecf20Sopenharmony_ci struct kfd_topology_device *ret = NULL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci down_read(&topology_lock); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci list_for_each_entry(top_dev, &topology_device_list, list) 768c2ecf20Sopenharmony_ci if (top_dev->gpu_id == gpu_id) { 778c2ecf20Sopenharmony_ci ret = top_dev; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci up_read(&topology_lock); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return ret; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct kfd_dev *kfd_device_by_id(uint32_t gpu_id) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci top_dev = kfd_topology_device_by_id(gpu_id); 918c2ecf20Sopenharmony_ci if (!top_dev) 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return top_dev->gpu; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev; 1008c2ecf20Sopenharmony_ci struct kfd_dev *device = NULL; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci down_read(&topology_lock); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci list_for_each_entry(top_dev, &topology_device_list, list) 1058c2ecf20Sopenharmony_ci if (top_dev->gpu && top_dev->gpu->pdev == pdev) { 1068c2ecf20Sopenharmony_ci device = top_dev->gpu; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci up_read(&topology_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return device; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistruct kfd_dev *kfd_device_by_kgd(const struct kgd_dev *kgd) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev; 1188c2ecf20Sopenharmony_ci struct kfd_dev *device = NULL; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci down_read(&topology_lock); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci list_for_each_entry(top_dev, &topology_device_list, list) 1238c2ecf20Sopenharmony_ci if (top_dev->gpu && top_dev->gpu->kgd == kgd) { 1248c2ecf20Sopenharmony_ci device = top_dev->gpu; 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci up_read(&topology_lock); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return device; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Called with write topology_lock acquired */ 1348c2ecf20Sopenharmony_cistatic void kfd_release_topology_device(struct kfd_topology_device *dev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 1378c2ecf20Sopenharmony_ci struct kfd_cache_properties *cache; 1388c2ecf20Sopenharmony_ci struct kfd_iolink_properties *iolink; 1398c2ecf20Sopenharmony_ci struct kfd_perf_properties *perf; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci list_del(&dev->list); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci while (dev->mem_props.next != &dev->mem_props) { 1448c2ecf20Sopenharmony_ci mem = container_of(dev->mem_props.next, 1458c2ecf20Sopenharmony_ci struct kfd_mem_properties, list); 1468c2ecf20Sopenharmony_ci list_del(&mem->list); 1478c2ecf20Sopenharmony_ci kfree(mem); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci while (dev->cache_props.next != &dev->cache_props) { 1518c2ecf20Sopenharmony_ci cache = container_of(dev->cache_props.next, 1528c2ecf20Sopenharmony_ci struct kfd_cache_properties, list); 1538c2ecf20Sopenharmony_ci list_del(&cache->list); 1548c2ecf20Sopenharmony_ci kfree(cache); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci while (dev->io_link_props.next != &dev->io_link_props) { 1588c2ecf20Sopenharmony_ci iolink = container_of(dev->io_link_props.next, 1598c2ecf20Sopenharmony_ci struct kfd_iolink_properties, list); 1608c2ecf20Sopenharmony_ci list_del(&iolink->list); 1618c2ecf20Sopenharmony_ci kfree(iolink); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci while (dev->perf_props.next != &dev->perf_props) { 1658c2ecf20Sopenharmony_ci perf = container_of(dev->perf_props.next, 1668c2ecf20Sopenharmony_ci struct kfd_perf_properties, list); 1678c2ecf20Sopenharmony_ci list_del(&perf->list); 1688c2ecf20Sopenharmony_ci kfree(perf); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci kfree(dev); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_civoid kfd_release_topology_device_list(struct list_head *device_list) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci while (!list_empty(device_list)) { 1798c2ecf20Sopenharmony_ci dev = list_first_entry(device_list, 1808c2ecf20Sopenharmony_ci struct kfd_topology_device, list); 1818c2ecf20Sopenharmony_ci kfd_release_topology_device(dev); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic void kfd_release_live_view(void) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci kfd_release_topology_device_list(&topology_device_list); 1888c2ecf20Sopenharmony_ci memset(&sys_props, 0, sizeof(sys_props)); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct kfd_topology_device *kfd_create_topology_device( 1928c2ecf20Sopenharmony_ci struct list_head *device_list) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci dev = kfd_alloc_struct(dev); 1978c2ecf20Sopenharmony_ci if (!dev) { 1988c2ecf20Sopenharmony_ci pr_err("No memory to allocate a topology device"); 1998c2ecf20Sopenharmony_ci return NULL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->mem_props); 2038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->cache_props); 2048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->io_link_props); 2058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->perf_props); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci list_add_tail(&dev->list, device_list); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return dev; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci#define sysfs_show_gen_prop(buffer, offs, fmt, ...) \ 2148c2ecf20Sopenharmony_ci (offs += snprintf(buffer+offs, PAGE_SIZE-offs, \ 2158c2ecf20Sopenharmony_ci fmt, __VA_ARGS__)) 2168c2ecf20Sopenharmony_ci#define sysfs_show_32bit_prop(buffer, offs, name, value) \ 2178c2ecf20Sopenharmony_ci sysfs_show_gen_prop(buffer, offs, "%s %u\n", name, value) 2188c2ecf20Sopenharmony_ci#define sysfs_show_64bit_prop(buffer, offs, name, value) \ 2198c2ecf20Sopenharmony_ci sysfs_show_gen_prop(buffer, offs, "%s %llu\n", name, value) 2208c2ecf20Sopenharmony_ci#define sysfs_show_32bit_val(buffer, offs, value) \ 2218c2ecf20Sopenharmony_ci sysfs_show_gen_prop(buffer, offs, "%u\n", value) 2228c2ecf20Sopenharmony_ci#define sysfs_show_str_val(buffer, offs, value) \ 2238c2ecf20Sopenharmony_ci sysfs_show_gen_prop(buffer, offs, "%s\n", value) 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic ssize_t sysprops_show(struct kobject *kobj, struct attribute *attr, 2268c2ecf20Sopenharmony_ci char *buffer) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int offs = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Making sure that the buffer is an empty string */ 2318c2ecf20Sopenharmony_ci buffer[0] = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (attr == &sys_props.attr_genid) { 2348c2ecf20Sopenharmony_ci sysfs_show_32bit_val(buffer, offs, 2358c2ecf20Sopenharmony_ci sys_props.generation_count); 2368c2ecf20Sopenharmony_ci } else if (attr == &sys_props.attr_props) { 2378c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "platform_oem", 2388c2ecf20Sopenharmony_ci sys_props.platform_oem); 2398c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "platform_id", 2408c2ecf20Sopenharmony_ci sys_props.platform_id); 2418c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "platform_rev", 2428c2ecf20Sopenharmony_ci sys_props.platform_rev); 2438c2ecf20Sopenharmony_ci } else { 2448c2ecf20Sopenharmony_ci offs = -EINVAL; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return offs; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void kfd_topology_kobj_release(struct kobject *kobj) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci kfree(kobj); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic const struct sysfs_ops sysprops_ops = { 2568c2ecf20Sopenharmony_ci .show = sysprops_show, 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic struct kobj_type sysprops_type = { 2608c2ecf20Sopenharmony_ci .release = kfd_topology_kobj_release, 2618c2ecf20Sopenharmony_ci .sysfs_ops = &sysprops_ops, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic ssize_t iolink_show(struct kobject *kobj, struct attribute *attr, 2658c2ecf20Sopenharmony_ci char *buffer) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int offs = 0; 2688c2ecf20Sopenharmony_ci struct kfd_iolink_properties *iolink; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Making sure that the buffer is an empty string */ 2718c2ecf20Sopenharmony_ci buffer[0] = 0; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci iolink = container_of(attr, struct kfd_iolink_properties, attr); 2748c2ecf20Sopenharmony_ci if (iolink->gpu && kfd_devcgroup_check_permission(iolink->gpu)) 2758c2ecf20Sopenharmony_ci return -EPERM; 2768c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "type", iolink->iolink_type); 2778c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "version_major", iolink->ver_maj); 2788c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "version_minor", iolink->ver_min); 2798c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "node_from", iolink->node_from); 2808c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "node_to", iolink->node_to); 2818c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "weight", iolink->weight); 2828c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "min_latency", iolink->min_latency); 2838c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "max_latency", iolink->max_latency); 2848c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "min_bandwidth", 2858c2ecf20Sopenharmony_ci iolink->min_bandwidth); 2868c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "max_bandwidth", 2878c2ecf20Sopenharmony_ci iolink->max_bandwidth); 2888c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "recommended_transfer_size", 2898c2ecf20Sopenharmony_ci iolink->rec_transfer_size); 2908c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "flags", iolink->flags); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return offs; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic const struct sysfs_ops iolink_ops = { 2968c2ecf20Sopenharmony_ci .show = iolink_show, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic struct kobj_type iolink_type = { 3008c2ecf20Sopenharmony_ci .release = kfd_topology_kobj_release, 3018c2ecf20Sopenharmony_ci .sysfs_ops = &iolink_ops, 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic ssize_t mem_show(struct kobject *kobj, struct attribute *attr, 3058c2ecf20Sopenharmony_ci char *buffer) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int offs = 0; 3088c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Making sure that the buffer is an empty string */ 3118c2ecf20Sopenharmony_ci buffer[0] = 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci mem = container_of(attr, struct kfd_mem_properties, attr); 3148c2ecf20Sopenharmony_ci if (mem->gpu && kfd_devcgroup_check_permission(mem->gpu)) 3158c2ecf20Sopenharmony_ci return -EPERM; 3168c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "heap_type", mem->heap_type); 3178c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "size_in_bytes", 3188c2ecf20Sopenharmony_ci mem->size_in_bytes); 3198c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "flags", mem->flags); 3208c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "width", mem->width); 3218c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "mem_clk_max", 3228c2ecf20Sopenharmony_ci mem->mem_clk_max); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return offs; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic const struct sysfs_ops mem_ops = { 3288c2ecf20Sopenharmony_ci .show = mem_show, 3298c2ecf20Sopenharmony_ci}; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic struct kobj_type mem_type = { 3328c2ecf20Sopenharmony_ci .release = kfd_topology_kobj_release, 3338c2ecf20Sopenharmony_ci .sysfs_ops = &mem_ops, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic ssize_t kfd_cache_show(struct kobject *kobj, struct attribute *attr, 3378c2ecf20Sopenharmony_ci char *buffer) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci int offs = 0; 3408c2ecf20Sopenharmony_ci uint32_t i, j; 3418c2ecf20Sopenharmony_ci struct kfd_cache_properties *cache; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Making sure that the buffer is an empty string */ 3448c2ecf20Sopenharmony_ci buffer[0] = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci cache = container_of(attr, struct kfd_cache_properties, attr); 3478c2ecf20Sopenharmony_ci if (cache->gpu && kfd_devcgroup_check_permission(cache->gpu)) 3488c2ecf20Sopenharmony_ci return -EPERM; 3498c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "processor_id_low", 3508c2ecf20Sopenharmony_ci cache->processor_id_low); 3518c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "level", cache->cache_level); 3528c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "size", cache->cache_size); 3538c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "cache_line_size", 3548c2ecf20Sopenharmony_ci cache->cacheline_size); 3558c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "cache_lines_per_tag", 3568c2ecf20Sopenharmony_ci cache->cachelines_per_tag); 3578c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "association", cache->cache_assoc); 3588c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "latency", cache->cache_latency); 3598c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "type", cache->cache_type); 3608c2ecf20Sopenharmony_ci offs += snprintf(buffer+offs, PAGE_SIZE-offs, "sibling_map "); 3618c2ecf20Sopenharmony_ci for (i = 0; i < CRAT_SIBLINGMAP_SIZE; i++) 3628c2ecf20Sopenharmony_ci for (j = 0; j < sizeof(cache->sibling_map[0])*8; j++) 3638c2ecf20Sopenharmony_ci /* Check each bit */ 3648c2ecf20Sopenharmony_ci offs += snprintf(buffer+offs, PAGE_SIZE-offs, "%d,", 3658c2ecf20Sopenharmony_ci (cache->sibling_map[i] >> j) & 1); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Replace the last "," with end of line */ 3688c2ecf20Sopenharmony_ci buffer[offs-1] = '\n'; 3698c2ecf20Sopenharmony_ci return offs; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct sysfs_ops cache_ops = { 3738c2ecf20Sopenharmony_ci .show = kfd_cache_show, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic struct kobj_type cache_type = { 3778c2ecf20Sopenharmony_ci .release = kfd_topology_kobj_release, 3788c2ecf20Sopenharmony_ci .sysfs_ops = &cache_ops, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/****** Sysfs of Performance Counters ******/ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistruct kfd_perf_attr { 3848c2ecf20Sopenharmony_ci struct kobj_attribute attr; 3858c2ecf20Sopenharmony_ci uint32_t data; 3868c2ecf20Sopenharmony_ci}; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic ssize_t perf_show(struct kobject *kobj, struct kobj_attribute *attrs, 3898c2ecf20Sopenharmony_ci char *buf) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci int offs = 0; 3928c2ecf20Sopenharmony_ci struct kfd_perf_attr *attr; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci buf[0] = 0; 3958c2ecf20Sopenharmony_ci attr = container_of(attrs, struct kfd_perf_attr, attr); 3968c2ecf20Sopenharmony_ci if (!attr->data) /* invalid data for PMC */ 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci else 3998c2ecf20Sopenharmony_ci return sysfs_show_32bit_val(buf, offs, attr->data); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#define KFD_PERF_DESC(_name, _data) \ 4038c2ecf20Sopenharmony_ci{ \ 4048c2ecf20Sopenharmony_ci .attr = __ATTR(_name, 0444, perf_show, NULL), \ 4058c2ecf20Sopenharmony_ci .data = _data, \ 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic struct kfd_perf_attr perf_attr_iommu[] = { 4098c2ecf20Sopenharmony_ci KFD_PERF_DESC(max_concurrent, 0), 4108c2ecf20Sopenharmony_ci KFD_PERF_DESC(num_counters, 0), 4118c2ecf20Sopenharmony_ci KFD_PERF_DESC(counter_ids, 0), 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci/****************************************/ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic ssize_t node_show(struct kobject *kobj, struct attribute *attr, 4168c2ecf20Sopenharmony_ci char *buffer) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci int offs = 0; 4198c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 4208c2ecf20Sopenharmony_ci uint32_t log_max_watch_addr; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Making sure that the buffer is an empty string */ 4238c2ecf20Sopenharmony_ci buffer[0] = 0; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (strcmp(attr->name, "gpu_id") == 0) { 4268c2ecf20Sopenharmony_ci dev = container_of(attr, struct kfd_topology_device, 4278c2ecf20Sopenharmony_ci attr_gpuid); 4288c2ecf20Sopenharmony_ci if (dev->gpu && kfd_devcgroup_check_permission(dev->gpu)) 4298c2ecf20Sopenharmony_ci return -EPERM; 4308c2ecf20Sopenharmony_ci return sysfs_show_32bit_val(buffer, offs, dev->gpu_id); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (strcmp(attr->name, "name") == 0) { 4348c2ecf20Sopenharmony_ci dev = container_of(attr, struct kfd_topology_device, 4358c2ecf20Sopenharmony_ci attr_name); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (dev->gpu && kfd_devcgroup_check_permission(dev->gpu)) 4388c2ecf20Sopenharmony_ci return -EPERM; 4398c2ecf20Sopenharmony_ci return sysfs_show_str_val(buffer, offs, dev->node_props.name); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci dev = container_of(attr, struct kfd_topology_device, 4438c2ecf20Sopenharmony_ci attr_props); 4448c2ecf20Sopenharmony_ci if (dev->gpu && kfd_devcgroup_check_permission(dev->gpu)) 4458c2ecf20Sopenharmony_ci return -EPERM; 4468c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "cpu_cores_count", 4478c2ecf20Sopenharmony_ci dev->node_props.cpu_cores_count); 4488c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "simd_count", 4498c2ecf20Sopenharmony_ci dev->gpu ? dev->node_props.simd_count : 0); 4508c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "mem_banks_count", 4518c2ecf20Sopenharmony_ci dev->node_props.mem_banks_count); 4528c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "caches_count", 4538c2ecf20Sopenharmony_ci dev->node_props.caches_count); 4548c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "io_links_count", 4558c2ecf20Sopenharmony_ci dev->node_props.io_links_count); 4568c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "cpu_core_id_base", 4578c2ecf20Sopenharmony_ci dev->node_props.cpu_core_id_base); 4588c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "simd_id_base", 4598c2ecf20Sopenharmony_ci dev->node_props.simd_id_base); 4608c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "max_waves_per_simd", 4618c2ecf20Sopenharmony_ci dev->node_props.max_waves_per_simd); 4628c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "lds_size_in_kb", 4638c2ecf20Sopenharmony_ci dev->node_props.lds_size_in_kb); 4648c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "gds_size_in_kb", 4658c2ecf20Sopenharmony_ci dev->node_props.gds_size_in_kb); 4668c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "num_gws", 4678c2ecf20Sopenharmony_ci dev->node_props.num_gws); 4688c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "wave_front_size", 4698c2ecf20Sopenharmony_ci dev->node_props.wave_front_size); 4708c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "array_count", 4718c2ecf20Sopenharmony_ci dev->node_props.array_count); 4728c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "simd_arrays_per_engine", 4738c2ecf20Sopenharmony_ci dev->node_props.simd_arrays_per_engine); 4748c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "cu_per_simd_array", 4758c2ecf20Sopenharmony_ci dev->node_props.cu_per_simd_array); 4768c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "simd_per_cu", 4778c2ecf20Sopenharmony_ci dev->node_props.simd_per_cu); 4788c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "max_slots_scratch_cu", 4798c2ecf20Sopenharmony_ci dev->node_props.max_slots_scratch_cu); 4808c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "vendor_id", 4818c2ecf20Sopenharmony_ci dev->node_props.vendor_id); 4828c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "device_id", 4838c2ecf20Sopenharmony_ci dev->node_props.device_id); 4848c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "location_id", 4858c2ecf20Sopenharmony_ci dev->node_props.location_id); 4868c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "domain", 4878c2ecf20Sopenharmony_ci dev->node_props.domain); 4888c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "drm_render_minor", 4898c2ecf20Sopenharmony_ci dev->node_props.drm_render_minor); 4908c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "hive_id", 4918c2ecf20Sopenharmony_ci dev->node_props.hive_id); 4928c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "num_sdma_engines", 4938c2ecf20Sopenharmony_ci dev->node_props.num_sdma_engines); 4948c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "num_sdma_xgmi_engines", 4958c2ecf20Sopenharmony_ci dev->node_props.num_sdma_xgmi_engines); 4968c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "num_sdma_queues_per_engine", 4978c2ecf20Sopenharmony_ci dev->node_props.num_sdma_queues_per_engine); 4988c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "num_cp_queues", 4998c2ecf20Sopenharmony_ci dev->node_props.num_cp_queues); 5008c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "unique_id", 5018c2ecf20Sopenharmony_ci dev->node_props.unique_id); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (dev->gpu) { 5048c2ecf20Sopenharmony_ci log_max_watch_addr = 5058c2ecf20Sopenharmony_ci __ilog2_u32(dev->gpu->device_info->num_of_watch_points); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (log_max_watch_addr) { 5088c2ecf20Sopenharmony_ci dev->node_props.capability |= 5098c2ecf20Sopenharmony_ci HSA_CAP_WATCH_POINTS_SUPPORTED; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci dev->node_props.capability |= 5128c2ecf20Sopenharmony_ci ((log_max_watch_addr << 5138c2ecf20Sopenharmony_ci HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) & 5148c2ecf20Sopenharmony_ci HSA_CAP_WATCH_POINTS_TOTALBITS_MASK); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (dev->gpu->device_info->asic_family == CHIP_TONGA) 5188c2ecf20Sopenharmony_ci dev->node_props.capability |= 5198c2ecf20Sopenharmony_ci HSA_CAP_AQL_QUEUE_DOUBLE_MAP; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "max_engine_clk_fcompute", 5228c2ecf20Sopenharmony_ci dev->node_props.max_engine_clk_fcompute); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci sysfs_show_64bit_prop(buffer, offs, "local_mem_size", 0ULL); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "fw_version", 5278c2ecf20Sopenharmony_ci dev->gpu->mec_fw_version); 5288c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "capability", 5298c2ecf20Sopenharmony_ci dev->node_props.capability); 5308c2ecf20Sopenharmony_ci sysfs_show_32bit_prop(buffer, offs, "sdma_fw_version", 5318c2ecf20Sopenharmony_ci dev->gpu->sdma_fw_version); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return sysfs_show_32bit_prop(buffer, offs, "max_engine_clk_ccompute", 5358c2ecf20Sopenharmony_ci cpufreq_quick_get_max(0)/1000); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct sysfs_ops node_ops = { 5398c2ecf20Sopenharmony_ci .show = node_show, 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic struct kobj_type node_type = { 5438c2ecf20Sopenharmony_ci .release = kfd_topology_kobj_release, 5448c2ecf20Sopenharmony_ci .sysfs_ops = &node_ops, 5458c2ecf20Sopenharmony_ci}; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void kfd_remove_sysfs_file(struct kobject *kobj, struct attribute *attr) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci sysfs_remove_file(kobj, attr); 5508c2ecf20Sopenharmony_ci kobject_del(kobj); 5518c2ecf20Sopenharmony_ci kobject_put(kobj); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic void kfd_remove_sysfs_node_entry(struct kfd_topology_device *dev) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct kfd_iolink_properties *iolink; 5578c2ecf20Sopenharmony_ci struct kfd_cache_properties *cache; 5588c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 5598c2ecf20Sopenharmony_ci struct kfd_perf_properties *perf; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (dev->kobj_iolink) { 5628c2ecf20Sopenharmony_ci list_for_each_entry(iolink, &dev->io_link_props, list) 5638c2ecf20Sopenharmony_ci if (iolink->kobj) { 5648c2ecf20Sopenharmony_ci kfd_remove_sysfs_file(iolink->kobj, 5658c2ecf20Sopenharmony_ci &iolink->attr); 5668c2ecf20Sopenharmony_ci iolink->kobj = NULL; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci kobject_del(dev->kobj_iolink); 5698c2ecf20Sopenharmony_ci kobject_put(dev->kobj_iolink); 5708c2ecf20Sopenharmony_ci dev->kobj_iolink = NULL; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (dev->kobj_cache) { 5748c2ecf20Sopenharmony_ci list_for_each_entry(cache, &dev->cache_props, list) 5758c2ecf20Sopenharmony_ci if (cache->kobj) { 5768c2ecf20Sopenharmony_ci kfd_remove_sysfs_file(cache->kobj, 5778c2ecf20Sopenharmony_ci &cache->attr); 5788c2ecf20Sopenharmony_ci cache->kobj = NULL; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci kobject_del(dev->kobj_cache); 5818c2ecf20Sopenharmony_ci kobject_put(dev->kobj_cache); 5828c2ecf20Sopenharmony_ci dev->kobj_cache = NULL; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (dev->kobj_mem) { 5868c2ecf20Sopenharmony_ci list_for_each_entry(mem, &dev->mem_props, list) 5878c2ecf20Sopenharmony_ci if (mem->kobj) { 5888c2ecf20Sopenharmony_ci kfd_remove_sysfs_file(mem->kobj, &mem->attr); 5898c2ecf20Sopenharmony_ci mem->kobj = NULL; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci kobject_del(dev->kobj_mem); 5928c2ecf20Sopenharmony_ci kobject_put(dev->kobj_mem); 5938c2ecf20Sopenharmony_ci dev->kobj_mem = NULL; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (dev->kobj_perf) { 5978c2ecf20Sopenharmony_ci list_for_each_entry(perf, &dev->perf_props, list) { 5988c2ecf20Sopenharmony_ci kfree(perf->attr_group); 5998c2ecf20Sopenharmony_ci perf->attr_group = NULL; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci kobject_del(dev->kobj_perf); 6028c2ecf20Sopenharmony_ci kobject_put(dev->kobj_perf); 6038c2ecf20Sopenharmony_ci dev->kobj_perf = NULL; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (dev->kobj_node) { 6078c2ecf20Sopenharmony_ci sysfs_remove_file(dev->kobj_node, &dev->attr_gpuid); 6088c2ecf20Sopenharmony_ci sysfs_remove_file(dev->kobj_node, &dev->attr_name); 6098c2ecf20Sopenharmony_ci sysfs_remove_file(dev->kobj_node, &dev->attr_props); 6108c2ecf20Sopenharmony_ci kobject_del(dev->kobj_node); 6118c2ecf20Sopenharmony_ci kobject_put(dev->kobj_node); 6128c2ecf20Sopenharmony_ci dev->kobj_node = NULL; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev, 6178c2ecf20Sopenharmony_ci uint32_t id) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct kfd_iolink_properties *iolink; 6208c2ecf20Sopenharmony_ci struct kfd_cache_properties *cache; 6218c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 6228c2ecf20Sopenharmony_ci struct kfd_perf_properties *perf; 6238c2ecf20Sopenharmony_ci int ret; 6248c2ecf20Sopenharmony_ci uint32_t i, num_attrs; 6258c2ecf20Sopenharmony_ci struct attribute **attrs; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (WARN_ON(dev->kobj_node)) 6288c2ecf20Sopenharmony_ci return -EEXIST; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * Creating the sysfs folders 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci dev->kobj_node = kfd_alloc_struct(dev->kobj_node); 6348c2ecf20Sopenharmony_ci if (!dev->kobj_node) 6358c2ecf20Sopenharmony_ci return -ENOMEM; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci ret = kobject_init_and_add(dev->kobj_node, &node_type, 6388c2ecf20Sopenharmony_ci sys_props.kobj_nodes, "%d", id); 6398c2ecf20Sopenharmony_ci if (ret < 0) { 6408c2ecf20Sopenharmony_ci kobject_put(dev->kobj_node); 6418c2ecf20Sopenharmony_ci return ret; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci dev->kobj_mem = kobject_create_and_add("mem_banks", dev->kobj_node); 6458c2ecf20Sopenharmony_ci if (!dev->kobj_mem) 6468c2ecf20Sopenharmony_ci return -ENOMEM; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci dev->kobj_cache = kobject_create_and_add("caches", dev->kobj_node); 6498c2ecf20Sopenharmony_ci if (!dev->kobj_cache) 6508c2ecf20Sopenharmony_ci return -ENOMEM; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci dev->kobj_iolink = kobject_create_and_add("io_links", dev->kobj_node); 6538c2ecf20Sopenharmony_ci if (!dev->kobj_iolink) 6548c2ecf20Sopenharmony_ci return -ENOMEM; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci dev->kobj_perf = kobject_create_and_add("perf", dev->kobj_node); 6578c2ecf20Sopenharmony_ci if (!dev->kobj_perf) 6588c2ecf20Sopenharmony_ci return -ENOMEM; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* 6618c2ecf20Sopenharmony_ci * Creating sysfs files for node properties 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ci dev->attr_gpuid.name = "gpu_id"; 6648c2ecf20Sopenharmony_ci dev->attr_gpuid.mode = KFD_SYSFS_FILE_MODE; 6658c2ecf20Sopenharmony_ci sysfs_attr_init(&dev->attr_gpuid); 6668c2ecf20Sopenharmony_ci dev->attr_name.name = "name"; 6678c2ecf20Sopenharmony_ci dev->attr_name.mode = KFD_SYSFS_FILE_MODE; 6688c2ecf20Sopenharmony_ci sysfs_attr_init(&dev->attr_name); 6698c2ecf20Sopenharmony_ci dev->attr_props.name = "properties"; 6708c2ecf20Sopenharmony_ci dev->attr_props.mode = KFD_SYSFS_FILE_MODE; 6718c2ecf20Sopenharmony_ci sysfs_attr_init(&dev->attr_props); 6728c2ecf20Sopenharmony_ci ret = sysfs_create_file(dev->kobj_node, &dev->attr_gpuid); 6738c2ecf20Sopenharmony_ci if (ret < 0) 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci ret = sysfs_create_file(dev->kobj_node, &dev->attr_name); 6768c2ecf20Sopenharmony_ci if (ret < 0) 6778c2ecf20Sopenharmony_ci return ret; 6788c2ecf20Sopenharmony_ci ret = sysfs_create_file(dev->kobj_node, &dev->attr_props); 6798c2ecf20Sopenharmony_ci if (ret < 0) 6808c2ecf20Sopenharmony_ci return ret; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci i = 0; 6838c2ecf20Sopenharmony_ci list_for_each_entry(mem, &dev->mem_props, list) { 6848c2ecf20Sopenharmony_ci mem->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 6858c2ecf20Sopenharmony_ci if (!mem->kobj) 6868c2ecf20Sopenharmony_ci return -ENOMEM; 6878c2ecf20Sopenharmony_ci ret = kobject_init_and_add(mem->kobj, &mem_type, 6888c2ecf20Sopenharmony_ci dev->kobj_mem, "%d", i); 6898c2ecf20Sopenharmony_ci if (ret < 0) { 6908c2ecf20Sopenharmony_ci kobject_put(mem->kobj); 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci mem->attr.name = "properties"; 6958c2ecf20Sopenharmony_ci mem->attr.mode = KFD_SYSFS_FILE_MODE; 6968c2ecf20Sopenharmony_ci sysfs_attr_init(&mem->attr); 6978c2ecf20Sopenharmony_ci ret = sysfs_create_file(mem->kobj, &mem->attr); 6988c2ecf20Sopenharmony_ci if (ret < 0) 6998c2ecf20Sopenharmony_ci return ret; 7008c2ecf20Sopenharmony_ci i++; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci i = 0; 7048c2ecf20Sopenharmony_ci list_for_each_entry(cache, &dev->cache_props, list) { 7058c2ecf20Sopenharmony_ci cache->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 7068c2ecf20Sopenharmony_ci if (!cache->kobj) 7078c2ecf20Sopenharmony_ci return -ENOMEM; 7088c2ecf20Sopenharmony_ci ret = kobject_init_and_add(cache->kobj, &cache_type, 7098c2ecf20Sopenharmony_ci dev->kobj_cache, "%d", i); 7108c2ecf20Sopenharmony_ci if (ret < 0) { 7118c2ecf20Sopenharmony_ci kobject_put(cache->kobj); 7128c2ecf20Sopenharmony_ci return ret; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci cache->attr.name = "properties"; 7168c2ecf20Sopenharmony_ci cache->attr.mode = KFD_SYSFS_FILE_MODE; 7178c2ecf20Sopenharmony_ci sysfs_attr_init(&cache->attr); 7188c2ecf20Sopenharmony_ci ret = sysfs_create_file(cache->kobj, &cache->attr); 7198c2ecf20Sopenharmony_ci if (ret < 0) 7208c2ecf20Sopenharmony_ci return ret; 7218c2ecf20Sopenharmony_ci i++; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci i = 0; 7258c2ecf20Sopenharmony_ci list_for_each_entry(iolink, &dev->io_link_props, list) { 7268c2ecf20Sopenharmony_ci iolink->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 7278c2ecf20Sopenharmony_ci if (!iolink->kobj) 7288c2ecf20Sopenharmony_ci return -ENOMEM; 7298c2ecf20Sopenharmony_ci ret = kobject_init_and_add(iolink->kobj, &iolink_type, 7308c2ecf20Sopenharmony_ci dev->kobj_iolink, "%d", i); 7318c2ecf20Sopenharmony_ci if (ret < 0) { 7328c2ecf20Sopenharmony_ci kobject_put(iolink->kobj); 7338c2ecf20Sopenharmony_ci return ret; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci iolink->attr.name = "properties"; 7378c2ecf20Sopenharmony_ci iolink->attr.mode = KFD_SYSFS_FILE_MODE; 7388c2ecf20Sopenharmony_ci sysfs_attr_init(&iolink->attr); 7398c2ecf20Sopenharmony_ci ret = sysfs_create_file(iolink->kobj, &iolink->attr); 7408c2ecf20Sopenharmony_ci if (ret < 0) 7418c2ecf20Sopenharmony_ci return ret; 7428c2ecf20Sopenharmony_ci i++; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* All hardware blocks have the same number of attributes. */ 7468c2ecf20Sopenharmony_ci num_attrs = ARRAY_SIZE(perf_attr_iommu); 7478c2ecf20Sopenharmony_ci list_for_each_entry(perf, &dev->perf_props, list) { 7488c2ecf20Sopenharmony_ci perf->attr_group = kzalloc(sizeof(struct kfd_perf_attr) 7498c2ecf20Sopenharmony_ci * num_attrs + sizeof(struct attribute_group), 7508c2ecf20Sopenharmony_ci GFP_KERNEL); 7518c2ecf20Sopenharmony_ci if (!perf->attr_group) 7528c2ecf20Sopenharmony_ci return -ENOMEM; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci attrs = (struct attribute **)(perf->attr_group + 1); 7558c2ecf20Sopenharmony_ci if (!strcmp(perf->block_name, "iommu")) { 7568c2ecf20Sopenharmony_ci /* Information of IOMMU's num_counters and counter_ids is shown 7578c2ecf20Sopenharmony_ci * under /sys/bus/event_source/devices/amd_iommu. We don't 7588c2ecf20Sopenharmony_ci * duplicate here. 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci perf_attr_iommu[0].data = perf->max_concurrent; 7618c2ecf20Sopenharmony_ci for (i = 0; i < num_attrs; i++) 7628c2ecf20Sopenharmony_ci attrs[i] = &perf_attr_iommu[i].attr.attr; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci perf->attr_group->name = perf->block_name; 7658c2ecf20Sopenharmony_ci perf->attr_group->attrs = attrs; 7668c2ecf20Sopenharmony_ci ret = sysfs_create_group(dev->kobj_perf, perf->attr_group); 7678c2ecf20Sopenharmony_ci if (ret < 0) 7688c2ecf20Sopenharmony_ci return ret; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* Called with write topology lock acquired */ 7758c2ecf20Sopenharmony_cistatic int kfd_build_sysfs_node_tree(void) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 7788c2ecf20Sopenharmony_ci int ret; 7798c2ecf20Sopenharmony_ci uint32_t i = 0; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) { 7828c2ecf20Sopenharmony_ci ret = kfd_build_sysfs_node_entry(dev, i); 7838c2ecf20Sopenharmony_ci if (ret < 0) 7848c2ecf20Sopenharmony_ci return ret; 7858c2ecf20Sopenharmony_ci i++; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/* Called with write topology lock acquired */ 7928c2ecf20Sopenharmony_cistatic void kfd_remove_sysfs_node_tree(void) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) 7978c2ecf20Sopenharmony_ci kfd_remove_sysfs_node_entry(dev); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int kfd_topology_update_sysfs(void) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci int ret; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (!sys_props.kobj_topology) { 8058c2ecf20Sopenharmony_ci sys_props.kobj_topology = 8068c2ecf20Sopenharmony_ci kfd_alloc_struct(sys_props.kobj_topology); 8078c2ecf20Sopenharmony_ci if (!sys_props.kobj_topology) 8088c2ecf20Sopenharmony_ci return -ENOMEM; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci ret = kobject_init_and_add(sys_props.kobj_topology, 8118c2ecf20Sopenharmony_ci &sysprops_type, &kfd_device->kobj, 8128c2ecf20Sopenharmony_ci "topology"); 8138c2ecf20Sopenharmony_ci if (ret < 0) { 8148c2ecf20Sopenharmony_ci kobject_put(sys_props.kobj_topology); 8158c2ecf20Sopenharmony_ci return ret; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci sys_props.kobj_nodes = kobject_create_and_add("nodes", 8198c2ecf20Sopenharmony_ci sys_props.kobj_topology); 8208c2ecf20Sopenharmony_ci if (!sys_props.kobj_nodes) 8218c2ecf20Sopenharmony_ci return -ENOMEM; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci sys_props.attr_genid.name = "generation_id"; 8248c2ecf20Sopenharmony_ci sys_props.attr_genid.mode = KFD_SYSFS_FILE_MODE; 8258c2ecf20Sopenharmony_ci sysfs_attr_init(&sys_props.attr_genid); 8268c2ecf20Sopenharmony_ci ret = sysfs_create_file(sys_props.kobj_topology, 8278c2ecf20Sopenharmony_ci &sys_props.attr_genid); 8288c2ecf20Sopenharmony_ci if (ret < 0) 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci sys_props.attr_props.name = "system_properties"; 8328c2ecf20Sopenharmony_ci sys_props.attr_props.mode = KFD_SYSFS_FILE_MODE; 8338c2ecf20Sopenharmony_ci sysfs_attr_init(&sys_props.attr_props); 8348c2ecf20Sopenharmony_ci ret = sysfs_create_file(sys_props.kobj_topology, 8358c2ecf20Sopenharmony_ci &sys_props.attr_props); 8368c2ecf20Sopenharmony_ci if (ret < 0) 8378c2ecf20Sopenharmony_ci return ret; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci kfd_remove_sysfs_node_tree(); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return kfd_build_sysfs_node_tree(); 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void kfd_topology_release_sysfs(void) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci kfd_remove_sysfs_node_tree(); 8488c2ecf20Sopenharmony_ci if (sys_props.kobj_topology) { 8498c2ecf20Sopenharmony_ci sysfs_remove_file(sys_props.kobj_topology, 8508c2ecf20Sopenharmony_ci &sys_props.attr_genid); 8518c2ecf20Sopenharmony_ci sysfs_remove_file(sys_props.kobj_topology, 8528c2ecf20Sopenharmony_ci &sys_props.attr_props); 8538c2ecf20Sopenharmony_ci if (sys_props.kobj_nodes) { 8548c2ecf20Sopenharmony_ci kobject_del(sys_props.kobj_nodes); 8558c2ecf20Sopenharmony_ci kobject_put(sys_props.kobj_nodes); 8568c2ecf20Sopenharmony_ci sys_props.kobj_nodes = NULL; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci kobject_del(sys_props.kobj_topology); 8598c2ecf20Sopenharmony_ci kobject_put(sys_props.kobj_topology); 8608c2ecf20Sopenharmony_ci sys_props.kobj_topology = NULL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/* Called with write topology_lock acquired */ 8658c2ecf20Sopenharmony_cistatic void kfd_topology_update_device_list(struct list_head *temp_list, 8668c2ecf20Sopenharmony_ci struct list_head *master_list) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci while (!list_empty(temp_list)) { 8698c2ecf20Sopenharmony_ci list_move_tail(temp_list->next, master_list); 8708c2ecf20Sopenharmony_ci sys_props.num_devices++; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic void kfd_debug_print_topology(void) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci down_read(&topology_lock); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci dev = list_last_entry(&topology_device_list, 8818c2ecf20Sopenharmony_ci struct kfd_topology_device, list); 8828c2ecf20Sopenharmony_ci if (dev) { 8838c2ecf20Sopenharmony_ci if (dev->node_props.cpu_cores_count && 8848c2ecf20Sopenharmony_ci dev->node_props.simd_count) { 8858c2ecf20Sopenharmony_ci pr_info("Topology: Add APU node [0x%0x:0x%0x]\n", 8868c2ecf20Sopenharmony_ci dev->node_props.device_id, 8878c2ecf20Sopenharmony_ci dev->node_props.vendor_id); 8888c2ecf20Sopenharmony_ci } else if (dev->node_props.cpu_cores_count) 8898c2ecf20Sopenharmony_ci pr_info("Topology: Add CPU node\n"); 8908c2ecf20Sopenharmony_ci else if (dev->node_props.simd_count) 8918c2ecf20Sopenharmony_ci pr_info("Topology: Add dGPU node [0x%0x:0x%0x]\n", 8928c2ecf20Sopenharmony_ci dev->node_props.device_id, 8938c2ecf20Sopenharmony_ci dev->node_props.vendor_id); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci up_read(&topology_lock); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* Helper function for intializing platform_xx members of 8998c2ecf20Sopenharmony_ci * kfd_system_properties. Uses OEM info from the last CPU/APU node. 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_cistatic void kfd_update_system_properties(void) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci down_read(&topology_lock); 9068c2ecf20Sopenharmony_ci dev = list_last_entry(&topology_device_list, 9078c2ecf20Sopenharmony_ci struct kfd_topology_device, list); 9088c2ecf20Sopenharmony_ci if (dev) { 9098c2ecf20Sopenharmony_ci sys_props.platform_id = 9108c2ecf20Sopenharmony_ci (*((uint64_t *)dev->oem_id)) & CRAT_OEMID_64BIT_MASK; 9118c2ecf20Sopenharmony_ci sys_props.platform_oem = *((uint64_t *)dev->oem_table_id); 9128c2ecf20Sopenharmony_ci sys_props.platform_rev = dev->oem_revision; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci up_read(&topology_lock); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic void find_system_memory(const struct dmi_header *dm, 9188c2ecf20Sopenharmony_ci void *private) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 9218c2ecf20Sopenharmony_ci u16 mem_width, mem_clock; 9228c2ecf20Sopenharmony_ci struct kfd_topology_device *kdev = 9238c2ecf20Sopenharmony_ci (struct kfd_topology_device *)private; 9248c2ecf20Sopenharmony_ci const u8 *dmi_data = (const u8 *)(dm + 1); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (dm->type == DMI_ENTRY_MEM_DEVICE && dm->length >= 0x15) { 9278c2ecf20Sopenharmony_ci mem_width = (u16)(*(const u16 *)(dmi_data + 0x6)); 9288c2ecf20Sopenharmony_ci mem_clock = (u16)(*(const u16 *)(dmi_data + 0x11)); 9298c2ecf20Sopenharmony_ci list_for_each_entry(mem, &kdev->mem_props, list) { 9308c2ecf20Sopenharmony_ci if (mem_width != 0xFFFF && mem_width != 0) 9318c2ecf20Sopenharmony_ci mem->width = mem_width; 9328c2ecf20Sopenharmony_ci if (mem_clock != 0) 9338c2ecf20Sopenharmony_ci mem->mem_clk_max = mem_clock; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci/* 9398c2ecf20Sopenharmony_ci * Performance counters information is not part of CRAT but we would like to 9408c2ecf20Sopenharmony_ci * put them in the sysfs under topology directory for Thunk to get the data. 9418c2ecf20Sopenharmony_ci * This function is called before updating the sysfs. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_cistatic int kfd_add_perf_to_topology(struct kfd_topology_device *kdev) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci /* These are the only counters supported so far */ 9468c2ecf20Sopenharmony_ci return kfd_iommu_add_perf_counters(kdev); 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci/* kfd_add_non_crat_information - Add information that is not currently 9508c2ecf20Sopenharmony_ci * defined in CRAT but is necessary for KFD topology 9518c2ecf20Sopenharmony_ci * @dev - topology device to which addition info is added 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_cistatic void kfd_add_non_crat_information(struct kfd_topology_device *kdev) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci /* Check if CPU only node. */ 9568c2ecf20Sopenharmony_ci if (!kdev->gpu) { 9578c2ecf20Sopenharmony_ci /* Add system memory information */ 9588c2ecf20Sopenharmony_ci dmi_walk(find_system_memory, kdev); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci /* TODO: For GPU node, rearrange code from kfd_topology_add_device */ 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/* kfd_is_acpi_crat_invalid - CRAT from ACPI is valid only for AMD APU devices. 9648c2ecf20Sopenharmony_ci * Ignore CRAT for all other devices. AMD APU is identified if both CPU 9658c2ecf20Sopenharmony_ci * and GPU cores are present. 9668c2ecf20Sopenharmony_ci * @device_list - topology device list created by parsing ACPI CRAT table. 9678c2ecf20Sopenharmony_ci * @return - TRUE if invalid, FALSE is valid. 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_cistatic bool kfd_is_acpi_crat_invalid(struct list_head *device_list) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci list_for_each_entry(dev, device_list, list) { 9748c2ecf20Sopenharmony_ci if (dev->node_props.cpu_cores_count && 9758c2ecf20Sopenharmony_ci dev->node_props.simd_count) 9768c2ecf20Sopenharmony_ci return false; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci pr_info("Ignoring ACPI CRAT on non-APU system\n"); 9798c2ecf20Sopenharmony_ci return true; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ciint kfd_topology_init(void) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci void *crat_image = NULL; 9858c2ecf20Sopenharmony_ci size_t image_size = 0; 9868c2ecf20Sopenharmony_ci int ret; 9878c2ecf20Sopenharmony_ci struct list_head temp_topology_device_list; 9888c2ecf20Sopenharmony_ci int cpu_only_node = 0; 9898c2ecf20Sopenharmony_ci struct kfd_topology_device *kdev; 9908c2ecf20Sopenharmony_ci int proximity_domain; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* topology_device_list - Master list of all topology devices 9938c2ecf20Sopenharmony_ci * temp_topology_device_list - temporary list created while parsing CRAT 9948c2ecf20Sopenharmony_ci * or VCRAT. Once parsing is complete the contents of list is moved to 9958c2ecf20Sopenharmony_ci * topology_device_list 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* Initialize the head for the both the lists */ 9998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&topology_device_list); 10008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&temp_topology_device_list); 10018c2ecf20Sopenharmony_ci init_rwsem(&topology_lock); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci memset(&sys_props, 0, sizeof(sys_props)); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Proximity domains in ACPI CRAT tables start counting at 10068c2ecf20Sopenharmony_ci * 0. The same should be true for virtual CRAT tables created 10078c2ecf20Sopenharmony_ci * at this stage. GPUs added later in kfd_topology_add_device 10088c2ecf20Sopenharmony_ci * use a counter. 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_ci proximity_domain = 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* 10138c2ecf20Sopenharmony_ci * Get the CRAT image from the ACPI. If ACPI doesn't have one 10148c2ecf20Sopenharmony_ci * or if ACPI CRAT is invalid create a virtual CRAT. 10158c2ecf20Sopenharmony_ci * NOTE: The current implementation expects all AMD APUs to have 10168c2ecf20Sopenharmony_ci * CRAT. If no CRAT is available, it is assumed to be a CPU 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci ret = kfd_create_crat_image_acpi(&crat_image, &image_size); 10198c2ecf20Sopenharmony_ci if (!ret) { 10208c2ecf20Sopenharmony_ci ret = kfd_parse_crat_table(crat_image, 10218c2ecf20Sopenharmony_ci &temp_topology_device_list, 10228c2ecf20Sopenharmony_ci proximity_domain); 10238c2ecf20Sopenharmony_ci if (ret || 10248c2ecf20Sopenharmony_ci kfd_is_acpi_crat_invalid(&temp_topology_device_list)) { 10258c2ecf20Sopenharmony_ci kfd_release_topology_device_list( 10268c2ecf20Sopenharmony_ci &temp_topology_device_list); 10278c2ecf20Sopenharmony_ci kfd_destroy_crat_image(crat_image); 10288c2ecf20Sopenharmony_ci crat_image = NULL; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (!crat_image) { 10338c2ecf20Sopenharmony_ci ret = kfd_create_crat_image_virtual(&crat_image, &image_size, 10348c2ecf20Sopenharmony_ci COMPUTE_UNIT_CPU, NULL, 10358c2ecf20Sopenharmony_ci proximity_domain); 10368c2ecf20Sopenharmony_ci cpu_only_node = 1; 10378c2ecf20Sopenharmony_ci if (ret) { 10388c2ecf20Sopenharmony_ci pr_err("Error creating VCRAT table for CPU\n"); 10398c2ecf20Sopenharmony_ci return ret; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci ret = kfd_parse_crat_table(crat_image, 10438c2ecf20Sopenharmony_ci &temp_topology_device_list, 10448c2ecf20Sopenharmony_ci proximity_domain); 10458c2ecf20Sopenharmony_ci if (ret) { 10468c2ecf20Sopenharmony_ci pr_err("Error parsing VCRAT table for CPU\n"); 10478c2ecf20Sopenharmony_ci goto err; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci kdev = list_first_entry(&temp_topology_device_list, 10528c2ecf20Sopenharmony_ci struct kfd_topology_device, list); 10538c2ecf20Sopenharmony_ci kfd_add_perf_to_topology(kdev); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci down_write(&topology_lock); 10568c2ecf20Sopenharmony_ci kfd_topology_update_device_list(&temp_topology_device_list, 10578c2ecf20Sopenharmony_ci &topology_device_list); 10588c2ecf20Sopenharmony_ci atomic_set(&topology_crat_proximity_domain, sys_props.num_devices-1); 10598c2ecf20Sopenharmony_ci ret = kfd_topology_update_sysfs(); 10608c2ecf20Sopenharmony_ci up_write(&topology_lock); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (!ret) { 10638c2ecf20Sopenharmony_ci sys_props.generation_count++; 10648c2ecf20Sopenharmony_ci kfd_update_system_properties(); 10658c2ecf20Sopenharmony_ci kfd_debug_print_topology(); 10668c2ecf20Sopenharmony_ci } else 10678c2ecf20Sopenharmony_ci pr_err("Failed to update topology in sysfs ret=%d\n", ret); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* For nodes with GPU, this information gets added 10708c2ecf20Sopenharmony_ci * when GPU is detected (kfd_topology_add_device). 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci if (cpu_only_node) { 10738c2ecf20Sopenharmony_ci /* Add additional information to CPU only node created above */ 10748c2ecf20Sopenharmony_ci down_write(&topology_lock); 10758c2ecf20Sopenharmony_ci kdev = list_first_entry(&topology_device_list, 10768c2ecf20Sopenharmony_ci struct kfd_topology_device, list); 10778c2ecf20Sopenharmony_ci up_write(&topology_lock); 10788c2ecf20Sopenharmony_ci kfd_add_non_crat_information(kdev); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cierr: 10828c2ecf20Sopenharmony_ci kfd_destroy_crat_image(crat_image); 10838c2ecf20Sopenharmony_ci return ret; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_civoid kfd_topology_shutdown(void) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci down_write(&topology_lock); 10898c2ecf20Sopenharmony_ci kfd_topology_release_sysfs(); 10908c2ecf20Sopenharmony_ci kfd_release_live_view(); 10918c2ecf20Sopenharmony_ci up_write(&topology_lock); 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci uint32_t hashout; 10978c2ecf20Sopenharmony_ci uint32_t buf[7]; 10988c2ecf20Sopenharmony_ci uint64_t local_mem_size; 10998c2ecf20Sopenharmony_ci int i; 11008c2ecf20Sopenharmony_ci struct kfd_local_mem_info local_mem_info; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (!gpu) 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci amdgpu_amdkfd_get_local_mem_info(gpu->kgd, &local_mem_info); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci local_mem_size = local_mem_info.local_mem_size_private + 11088c2ecf20Sopenharmony_ci local_mem_info.local_mem_size_public; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci buf[0] = gpu->pdev->devfn; 11118c2ecf20Sopenharmony_ci buf[1] = gpu->pdev->subsystem_vendor | 11128c2ecf20Sopenharmony_ci (gpu->pdev->subsystem_device << 16); 11138c2ecf20Sopenharmony_ci buf[2] = pci_domain_nr(gpu->pdev->bus); 11148c2ecf20Sopenharmony_ci buf[3] = gpu->pdev->device; 11158c2ecf20Sopenharmony_ci buf[4] = gpu->pdev->bus->number; 11168c2ecf20Sopenharmony_ci buf[5] = lower_32_bits(local_mem_size); 11178c2ecf20Sopenharmony_ci buf[6] = upper_32_bits(local_mem_size); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci for (i = 0, hashout = 0; i < 7; i++) 11208c2ecf20Sopenharmony_ci hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci return hashout; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci/* kfd_assign_gpu - Attach @gpu to the correct kfd topology device. If 11258c2ecf20Sopenharmony_ci * the GPU device is not already present in the topology device 11268c2ecf20Sopenharmony_ci * list then return NULL. This means a new topology device has to 11278c2ecf20Sopenharmony_ci * be created for this GPU. 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_cistatic struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 11328c2ecf20Sopenharmony_ci struct kfd_topology_device *out_dev = NULL; 11338c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 11348c2ecf20Sopenharmony_ci struct kfd_cache_properties *cache; 11358c2ecf20Sopenharmony_ci struct kfd_iolink_properties *iolink; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci down_write(&topology_lock); 11388c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) { 11398c2ecf20Sopenharmony_ci /* Discrete GPUs need their own topology device list 11408c2ecf20Sopenharmony_ci * entries. Don't assign them to CPU/APU nodes. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ci if (!gpu->use_iommu_v2 && 11438c2ecf20Sopenharmony_ci dev->node_props.cpu_cores_count) 11448c2ecf20Sopenharmony_ci continue; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (!dev->gpu && (dev->node_props.simd_count > 0)) { 11478c2ecf20Sopenharmony_ci dev->gpu = gpu; 11488c2ecf20Sopenharmony_ci out_dev = dev; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci list_for_each_entry(mem, &dev->mem_props, list) 11518c2ecf20Sopenharmony_ci mem->gpu = dev->gpu; 11528c2ecf20Sopenharmony_ci list_for_each_entry(cache, &dev->cache_props, list) 11538c2ecf20Sopenharmony_ci cache->gpu = dev->gpu; 11548c2ecf20Sopenharmony_ci list_for_each_entry(iolink, &dev->io_link_props, list) 11558c2ecf20Sopenharmony_ci iolink->gpu = dev->gpu; 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci up_write(&topology_lock); 11608c2ecf20Sopenharmony_ci return out_dev; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic void kfd_notify_gpu_change(uint32_t gpu_id, int arrival) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci /* 11668c2ecf20Sopenharmony_ci * TODO: Generate an event for thunk about the arrival/removal 11678c2ecf20Sopenharmony_ci * of the GPU 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci/* kfd_fill_mem_clk_max_info - Since CRAT doesn't have memory clock info, 11728c2ecf20Sopenharmony_ci * patch this after CRAT parsing. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_cistatic void kfd_fill_mem_clk_max_info(struct kfd_topology_device *dev) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct kfd_mem_properties *mem; 11778c2ecf20Sopenharmony_ci struct kfd_local_mem_info local_mem_info; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (!dev) 11808c2ecf20Sopenharmony_ci return; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Currently, amdgpu driver (amdgpu_mc) deals only with GPUs with 11838c2ecf20Sopenharmony_ci * single bank of VRAM local memory. 11848c2ecf20Sopenharmony_ci * for dGPUs - VCRAT reports only one bank of Local Memory 11858c2ecf20Sopenharmony_ci * for APUs - If CRAT from ACPI reports more than one bank, then 11868c2ecf20Sopenharmony_ci * all the banks will report the same mem_clk_max information 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ci amdgpu_amdkfd_get_local_mem_info(dev->gpu->kgd, &local_mem_info); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci list_for_each_entry(mem, &dev->mem_props, list) 11918c2ecf20Sopenharmony_ci mem->mem_clk_max = local_mem_info.mem_clk_max; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic void kfd_fill_iolink_non_crat_info(struct kfd_topology_device *dev) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct kfd_iolink_properties *link, *cpu_link; 11978c2ecf20Sopenharmony_ci struct kfd_topology_device *cpu_dev; 11988c2ecf20Sopenharmony_ci uint32_t cap; 11998c2ecf20Sopenharmony_ci uint32_t cpu_flag = CRAT_IOLINK_FLAGS_ENABLED; 12008c2ecf20Sopenharmony_ci uint32_t flag = CRAT_IOLINK_FLAGS_ENABLED; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci if (!dev || !dev->gpu) 12038c2ecf20Sopenharmony_ci return; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci pcie_capability_read_dword(dev->gpu->pdev, 12068c2ecf20Sopenharmony_ci PCI_EXP_DEVCAP2, &cap); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (!(cap & (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | 12098c2ecf20Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP64))) 12108c2ecf20Sopenharmony_ci cpu_flag |= CRAT_IOLINK_FLAGS_NO_ATOMICS_32_BIT | 12118c2ecf20Sopenharmony_ci CRAT_IOLINK_FLAGS_NO_ATOMICS_64_BIT; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (!dev->gpu->pci_atomic_requested || 12148c2ecf20Sopenharmony_ci dev->gpu->device_info->asic_family == CHIP_HAWAII) 12158c2ecf20Sopenharmony_ci flag |= CRAT_IOLINK_FLAGS_NO_ATOMICS_32_BIT | 12168c2ecf20Sopenharmony_ci CRAT_IOLINK_FLAGS_NO_ATOMICS_64_BIT; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* GPU only creates direct links so apply flags setting to all */ 12198c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->io_link_props, list) { 12208c2ecf20Sopenharmony_ci link->flags = flag; 12218c2ecf20Sopenharmony_ci cpu_dev = kfd_topology_device_by_proximity_domain( 12228c2ecf20Sopenharmony_ci link->node_to); 12238c2ecf20Sopenharmony_ci if (cpu_dev) { 12248c2ecf20Sopenharmony_ci list_for_each_entry(cpu_link, 12258c2ecf20Sopenharmony_ci &cpu_dev->io_link_props, list) 12268c2ecf20Sopenharmony_ci if (cpu_link->node_to == link->node_from) 12278c2ecf20Sopenharmony_ci cpu_link->flags = cpu_flag; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ciint kfd_topology_add_device(struct kfd_dev *gpu) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci uint32_t gpu_id; 12358c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 12368c2ecf20Sopenharmony_ci struct kfd_cu_info cu_info; 12378c2ecf20Sopenharmony_ci int res = 0; 12388c2ecf20Sopenharmony_ci struct list_head temp_topology_device_list; 12398c2ecf20Sopenharmony_ci void *crat_image = NULL; 12408c2ecf20Sopenharmony_ci size_t image_size = 0; 12418c2ecf20Sopenharmony_ci int proximity_domain; 12428c2ecf20Sopenharmony_ci struct amdgpu_device *adev; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&temp_topology_device_list); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci gpu_id = kfd_generate_gpu_id(gpu); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci proximity_domain = atomic_inc_return(&topology_crat_proximity_domain); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /* Check to see if this gpu device exists in the topology_device_list. 12538c2ecf20Sopenharmony_ci * If so, assign the gpu to that device, 12548c2ecf20Sopenharmony_ci * else create a Virtual CRAT for this gpu device and then parse that 12558c2ecf20Sopenharmony_ci * CRAT to create a new topology device. Once created assign the gpu to 12568c2ecf20Sopenharmony_ci * that topology device 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_ci dev = kfd_assign_gpu(gpu); 12598c2ecf20Sopenharmony_ci if (!dev) { 12608c2ecf20Sopenharmony_ci res = kfd_create_crat_image_virtual(&crat_image, &image_size, 12618c2ecf20Sopenharmony_ci COMPUTE_UNIT_GPU, gpu, 12628c2ecf20Sopenharmony_ci proximity_domain); 12638c2ecf20Sopenharmony_ci if (res) { 12648c2ecf20Sopenharmony_ci pr_err("Error creating VCRAT for GPU (ID: 0x%x)\n", 12658c2ecf20Sopenharmony_ci gpu_id); 12668c2ecf20Sopenharmony_ci return res; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci res = kfd_parse_crat_table(crat_image, 12698c2ecf20Sopenharmony_ci &temp_topology_device_list, 12708c2ecf20Sopenharmony_ci proximity_domain); 12718c2ecf20Sopenharmony_ci if (res) { 12728c2ecf20Sopenharmony_ci pr_err("Error parsing VCRAT for GPU (ID: 0x%x)\n", 12738c2ecf20Sopenharmony_ci gpu_id); 12748c2ecf20Sopenharmony_ci goto err; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci down_write(&topology_lock); 12788c2ecf20Sopenharmony_ci kfd_topology_update_device_list(&temp_topology_device_list, 12798c2ecf20Sopenharmony_ci &topology_device_list); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Update the SYSFS tree, since we added another topology 12828c2ecf20Sopenharmony_ci * device 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci res = kfd_topology_update_sysfs(); 12858c2ecf20Sopenharmony_ci up_write(&topology_lock); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (!res) 12888c2ecf20Sopenharmony_ci sys_props.generation_count++; 12898c2ecf20Sopenharmony_ci else 12908c2ecf20Sopenharmony_ci pr_err("Failed to update GPU (ID: 0x%x) to sysfs topology. res=%d\n", 12918c2ecf20Sopenharmony_ci gpu_id, res); 12928c2ecf20Sopenharmony_ci dev = kfd_assign_gpu(gpu); 12938c2ecf20Sopenharmony_ci if (WARN_ON(!dev)) { 12948c2ecf20Sopenharmony_ci res = -ENODEV; 12958c2ecf20Sopenharmony_ci goto err; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci dev->gpu_id = gpu_id; 13008c2ecf20Sopenharmony_ci gpu->id = gpu_id; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci /* TODO: Move the following lines to function 13038c2ecf20Sopenharmony_ci * kfd_add_non_crat_information 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* Fill-in additional information that is not available in CRAT but 13078c2ecf20Sopenharmony_ci * needed for the topology 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci amdgpu_amdkfd_get_cu_info(dev->gpu->kgd, &cu_info); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci strncpy(dev->node_props.name, gpu->device_info->asic_name, 13138c2ecf20Sopenharmony_ci KFD_TOPOLOGY_PUBLIC_NAME_SIZE); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci dev->node_props.simd_arrays_per_engine = 13168c2ecf20Sopenharmony_ci cu_info.num_shader_arrays_per_engine; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci dev->node_props.vendor_id = gpu->pdev->vendor; 13198c2ecf20Sopenharmony_ci dev->node_props.device_id = gpu->pdev->device; 13208c2ecf20Sopenharmony_ci dev->node_props.capability |= 13218c2ecf20Sopenharmony_ci ((amdgpu_amdkfd_get_asic_rev_id(dev->gpu->kgd) << 13228c2ecf20Sopenharmony_ci HSA_CAP_ASIC_REVISION_SHIFT) & 13238c2ecf20Sopenharmony_ci HSA_CAP_ASIC_REVISION_MASK); 13248c2ecf20Sopenharmony_ci dev->node_props.location_id = pci_dev_id(gpu->pdev); 13258c2ecf20Sopenharmony_ci dev->node_props.domain = pci_domain_nr(gpu->pdev->bus); 13268c2ecf20Sopenharmony_ci dev->node_props.max_engine_clk_fcompute = 13278c2ecf20Sopenharmony_ci amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->kgd); 13288c2ecf20Sopenharmony_ci dev->node_props.max_engine_clk_ccompute = 13298c2ecf20Sopenharmony_ci cpufreq_quick_get_max(0) / 1000; 13308c2ecf20Sopenharmony_ci dev->node_props.drm_render_minor = 13318c2ecf20Sopenharmony_ci gpu->shared_resources.drm_render_minor; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci dev->node_props.hive_id = gpu->hive_id; 13348c2ecf20Sopenharmony_ci dev->node_props.num_sdma_engines = gpu->device_info->num_sdma_engines; 13358c2ecf20Sopenharmony_ci dev->node_props.num_sdma_xgmi_engines = 13368c2ecf20Sopenharmony_ci gpu->device_info->num_xgmi_sdma_engines; 13378c2ecf20Sopenharmony_ci dev->node_props.num_sdma_queues_per_engine = 13388c2ecf20Sopenharmony_ci gpu->device_info->num_sdma_queues_per_engine; 13398c2ecf20Sopenharmony_ci dev->node_props.num_gws = (dev->gpu->gws && 13408c2ecf20Sopenharmony_ci dev->gpu->dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) ? 13418c2ecf20Sopenharmony_ci amdgpu_amdkfd_get_num_gws(dev->gpu->kgd) : 0; 13428c2ecf20Sopenharmony_ci dev->node_props.num_cp_queues = get_cp_queues_num(dev->gpu->dqm); 13438c2ecf20Sopenharmony_ci dev->node_props.unique_id = gpu->unique_id; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci kfd_fill_mem_clk_max_info(dev); 13468c2ecf20Sopenharmony_ci kfd_fill_iolink_non_crat_info(dev); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci switch (dev->gpu->device_info->asic_family) { 13498c2ecf20Sopenharmony_ci case CHIP_KAVERI: 13508c2ecf20Sopenharmony_ci case CHIP_HAWAII: 13518c2ecf20Sopenharmony_ci case CHIP_TONGA: 13528c2ecf20Sopenharmony_ci dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_PRE_1_0 << 13538c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) & 13548c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); 13558c2ecf20Sopenharmony_ci break; 13568c2ecf20Sopenharmony_ci case CHIP_CARRIZO: 13578c2ecf20Sopenharmony_ci case CHIP_FIJI: 13588c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 13598c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 13608c2ecf20Sopenharmony_ci case CHIP_POLARIS12: 13618c2ecf20Sopenharmony_ci case CHIP_VEGAM: 13628c2ecf20Sopenharmony_ci pr_debug("Adding doorbell packet type capability\n"); 13638c2ecf20Sopenharmony_ci dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_1_0 << 13648c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) & 13658c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); 13668c2ecf20Sopenharmony_ci break; 13678c2ecf20Sopenharmony_ci case CHIP_VEGA10: 13688c2ecf20Sopenharmony_ci case CHIP_VEGA12: 13698c2ecf20Sopenharmony_ci case CHIP_VEGA20: 13708c2ecf20Sopenharmony_ci case CHIP_RAVEN: 13718c2ecf20Sopenharmony_ci case CHIP_RENOIR: 13728c2ecf20Sopenharmony_ci case CHIP_ARCTURUS: 13738c2ecf20Sopenharmony_ci case CHIP_NAVI10: 13748c2ecf20Sopenharmony_ci case CHIP_NAVI12: 13758c2ecf20Sopenharmony_ci case CHIP_NAVI14: 13768c2ecf20Sopenharmony_ci case CHIP_SIENNA_CICHLID: 13778c2ecf20Sopenharmony_ci case CHIP_NAVY_FLOUNDER: 13788c2ecf20Sopenharmony_ci dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_2_0 << 13798c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) & 13808c2ecf20Sopenharmony_ci HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); 13818c2ecf20Sopenharmony_ci break; 13828c2ecf20Sopenharmony_ci default: 13838c2ecf20Sopenharmony_ci WARN(1, "Unexpected ASIC family %u", 13848c2ecf20Sopenharmony_ci dev->gpu->device_info->asic_family); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* 13888c2ecf20Sopenharmony_ci * Overwrite ATS capability according to needs_iommu_device to fix 13898c2ecf20Sopenharmony_ci * potential missing corresponding bit in CRAT of BIOS. 13908c2ecf20Sopenharmony_ci */ 13918c2ecf20Sopenharmony_ci if (dev->gpu->use_iommu_v2) 13928c2ecf20Sopenharmony_ci dev->node_props.capability |= HSA_CAP_ATS_PRESENT; 13938c2ecf20Sopenharmony_ci else 13948c2ecf20Sopenharmony_ci dev->node_props.capability &= ~HSA_CAP_ATS_PRESENT; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* Fix errors in CZ CRAT. 13978c2ecf20Sopenharmony_ci * simd_count: Carrizo CRAT reports wrong simd_count, probably 13988c2ecf20Sopenharmony_ci * because it doesn't consider masked out CUs 13998c2ecf20Sopenharmony_ci * max_waves_per_simd: Carrizo reports wrong max_waves_per_simd 14008c2ecf20Sopenharmony_ci */ 14018c2ecf20Sopenharmony_ci if (dev->gpu->device_info->asic_family == CHIP_CARRIZO) { 14028c2ecf20Sopenharmony_ci dev->node_props.simd_count = 14038c2ecf20Sopenharmony_ci cu_info.simd_per_cu * cu_info.cu_active_number; 14048c2ecf20Sopenharmony_ci dev->node_props.max_waves_per_simd = 10; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci adev = (struct amdgpu_device *)(dev->gpu->kgd); 14088c2ecf20Sopenharmony_ci /* kfd only concerns sram ecc on GFX and HBM ecc on UMC */ 14098c2ecf20Sopenharmony_ci dev->node_props.capability |= 14108c2ecf20Sopenharmony_ci ((adev->ras_features & BIT(AMDGPU_RAS_BLOCK__GFX)) != 0) ? 14118c2ecf20Sopenharmony_ci HSA_CAP_SRAM_EDCSUPPORTED : 0; 14128c2ecf20Sopenharmony_ci dev->node_props.capability |= ((adev->ras_features & BIT(AMDGPU_RAS_BLOCK__UMC)) != 0) ? 14138c2ecf20Sopenharmony_ci HSA_CAP_MEM_EDCSUPPORTED : 0; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (adev->asic_type != CHIP_VEGA10) 14168c2ecf20Sopenharmony_ci dev->node_props.capability |= (adev->ras_features != 0) ? 14178c2ecf20Sopenharmony_ci HSA_CAP_RASEVENTNOTIFY : 0; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci kfd_debug_print_topology(); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (!res) 14228c2ecf20Sopenharmony_ci kfd_notify_gpu_change(gpu_id, 1); 14238c2ecf20Sopenharmony_cierr: 14248c2ecf20Sopenharmony_ci kfd_destroy_crat_image(crat_image); 14258c2ecf20Sopenharmony_ci return res; 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ciint kfd_topology_remove_device(struct kfd_dev *gpu) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct kfd_topology_device *dev, *tmp; 14318c2ecf20Sopenharmony_ci uint32_t gpu_id; 14328c2ecf20Sopenharmony_ci int res = -ENODEV; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci down_write(&topology_lock); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &topology_device_list, list) 14378c2ecf20Sopenharmony_ci if (dev->gpu == gpu) { 14388c2ecf20Sopenharmony_ci gpu_id = dev->gpu_id; 14398c2ecf20Sopenharmony_ci kfd_remove_sysfs_node_entry(dev); 14408c2ecf20Sopenharmony_ci kfd_release_topology_device(dev); 14418c2ecf20Sopenharmony_ci sys_props.num_devices--; 14428c2ecf20Sopenharmony_ci res = 0; 14438c2ecf20Sopenharmony_ci if (kfd_topology_update_sysfs() < 0) 14448c2ecf20Sopenharmony_ci kfd_topology_release_sysfs(); 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci up_write(&topology_lock); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (!res) 14518c2ecf20Sopenharmony_ci kfd_notify_gpu_change(gpu_id, 0); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci return res; 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci/* kfd_topology_enum_kfd_devices - Enumerate through all devices in KFD 14578c2ecf20Sopenharmony_ci * topology. If GPU device is found @idx, then valid kfd_dev pointer is 14588c2ecf20Sopenharmony_ci * returned through @kdev 14598c2ecf20Sopenharmony_ci * Return - 0: On success (@kdev will be NULL for non GPU nodes) 14608c2ecf20Sopenharmony_ci * -1: If end of list 14618c2ecf20Sopenharmony_ci */ 14628c2ecf20Sopenharmony_ciint kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci struct kfd_topology_device *top_dev; 14668c2ecf20Sopenharmony_ci uint8_t device_idx = 0; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci *kdev = NULL; 14698c2ecf20Sopenharmony_ci down_read(&topology_lock); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci list_for_each_entry(top_dev, &topology_device_list, list) { 14728c2ecf20Sopenharmony_ci if (device_idx == idx) { 14738c2ecf20Sopenharmony_ci *kdev = top_dev->gpu; 14748c2ecf20Sopenharmony_ci up_read(&topology_lock); 14758c2ecf20Sopenharmony_ci return 0; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci device_idx++; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci up_read(&topology_lock); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci return -1; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic int kfd_cpumask_to_apic_id(const struct cpumask *cpumask) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci int first_cpu_of_numa_node; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (!cpumask || cpumask == cpu_none_mask) 14928c2ecf20Sopenharmony_ci return -1; 14938c2ecf20Sopenharmony_ci first_cpu_of_numa_node = cpumask_first(cpumask); 14948c2ecf20Sopenharmony_ci if (first_cpu_of_numa_node >= nr_cpu_ids) 14958c2ecf20Sopenharmony_ci return -1; 14968c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 14978c2ecf20Sopenharmony_ci return cpu_data(first_cpu_of_numa_node).apicid; 14988c2ecf20Sopenharmony_ci#else 14998c2ecf20Sopenharmony_ci return first_cpu_of_numa_node; 15008c2ecf20Sopenharmony_ci#endif 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci/* kfd_numa_node_to_apic_id - Returns the APIC ID of the first logical processor 15048c2ecf20Sopenharmony_ci * of the given NUMA node (numa_node_id) 15058c2ecf20Sopenharmony_ci * Return -1 on failure 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_ciint kfd_numa_node_to_apic_id(int numa_node_id) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci if (numa_node_id == -1) { 15108c2ecf20Sopenharmony_ci pr_warn("Invalid NUMA Node. Use online CPU mask\n"); 15118c2ecf20Sopenharmony_ci return kfd_cpumask_to_apic_id(cpu_online_mask); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id)); 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_civoid kfd_double_confirm_iommu_support(struct kfd_dev *gpu) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci gpu->use_iommu_v2 = false; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (!gpu->device_info->needs_iommu_device) 15238c2ecf20Sopenharmony_ci return; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci down_read(&topology_lock); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* Only use IOMMUv2 if there is an APU topology node with no GPU 15288c2ecf20Sopenharmony_ci * assigned yet. This GPU will be assigned to it. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) 15318c2ecf20Sopenharmony_ci if (dev->node_props.cpu_cores_count && 15328c2ecf20Sopenharmony_ci dev->node_props.simd_count && 15338c2ecf20Sopenharmony_ci !dev->gpu) 15348c2ecf20Sopenharmony_ci gpu->use_iommu_v2 = true; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci up_read(&topology_lock); 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ciint kfd_debugfs_hqds_by_device(struct seq_file *m, void *data) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 15448c2ecf20Sopenharmony_ci unsigned int i = 0; 15458c2ecf20Sopenharmony_ci int r = 0; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci down_read(&topology_lock); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) { 15508c2ecf20Sopenharmony_ci if (!dev->gpu) { 15518c2ecf20Sopenharmony_ci i++; 15528c2ecf20Sopenharmony_ci continue; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci seq_printf(m, "Node %u, gpu_id %x:\n", i++, dev->gpu->id); 15568c2ecf20Sopenharmony_ci r = dqm_debugfs_hqds(m, dev->gpu->dqm); 15578c2ecf20Sopenharmony_ci if (r) 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci up_read(&topology_lock); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return r; 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ciint kfd_debugfs_rls_by_device(struct seq_file *m, void *data) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci struct kfd_topology_device *dev; 15698c2ecf20Sopenharmony_ci unsigned int i = 0; 15708c2ecf20Sopenharmony_ci int r = 0; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci down_read(&topology_lock); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci list_for_each_entry(dev, &topology_device_list, list) { 15758c2ecf20Sopenharmony_ci if (!dev->gpu) { 15768c2ecf20Sopenharmony_ci i++; 15778c2ecf20Sopenharmony_ci continue; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci seq_printf(m, "Node %u, gpu_id %x:\n", i++, dev->gpu->id); 15818c2ecf20Sopenharmony_ci r = pm_debugfs_runlist(m, &dev->gpu->dqm->packets); 15828c2ecf20Sopenharmony_ci if (r) 15838c2ecf20Sopenharmony_ci break; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci up_read(&topology_lock); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci return r; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci#endif 1592