15b5c4e40SEvgeny Pinchuk /* 25b5c4e40SEvgeny Pinchuk * Copyright 2014 Advanced Micro Devices, Inc. 35b5c4e40SEvgeny Pinchuk * 45b5c4e40SEvgeny Pinchuk * Permission is hereby granted, free of charge, to any person obtaining a 55b5c4e40SEvgeny Pinchuk * copy of this software and associated documentation files (the "Software"), 65b5c4e40SEvgeny Pinchuk * to deal in the Software without restriction, including without limitation 75b5c4e40SEvgeny Pinchuk * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85b5c4e40SEvgeny Pinchuk * and/or sell copies of the Software, and to permit persons to whom the 95b5c4e40SEvgeny Pinchuk * Software is furnished to do so, subject to the following conditions: 105b5c4e40SEvgeny Pinchuk * 115b5c4e40SEvgeny Pinchuk * The above copyright notice and this permission notice shall be included in 125b5c4e40SEvgeny Pinchuk * all copies or substantial portions of the Software. 135b5c4e40SEvgeny Pinchuk * 145b5c4e40SEvgeny Pinchuk * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155b5c4e40SEvgeny Pinchuk * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165b5c4e40SEvgeny Pinchuk * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175b5c4e40SEvgeny Pinchuk * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 185b5c4e40SEvgeny Pinchuk * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 195b5c4e40SEvgeny Pinchuk * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 205b5c4e40SEvgeny Pinchuk * OTHER DEALINGS IN THE SOFTWARE. 215b5c4e40SEvgeny Pinchuk */ 225b5c4e40SEvgeny Pinchuk 235b5c4e40SEvgeny Pinchuk #include <linux/types.h> 245b5c4e40SEvgeny Pinchuk #include <linux/kernel.h> 255b5c4e40SEvgeny Pinchuk #include <linux/pci.h> 265b5c4e40SEvgeny Pinchuk #include <linux/errno.h> 275b5c4e40SEvgeny Pinchuk #include <linux/acpi.h> 285b5c4e40SEvgeny Pinchuk #include <linux/hash.h> 295b5c4e40SEvgeny Pinchuk #include <linux/cpufreq.h> 30f7c826adSAlexey Skidanov #include <linux/log2.h> 315b5c4e40SEvgeny Pinchuk 325b5c4e40SEvgeny Pinchuk #include "kfd_priv.h" 335b5c4e40SEvgeny Pinchuk #include "kfd_crat.h" 345b5c4e40SEvgeny Pinchuk #include "kfd_topology.h" 355b5c4e40SEvgeny Pinchuk 365b5c4e40SEvgeny Pinchuk static struct list_head topology_device_list; 375b5c4e40SEvgeny Pinchuk static int topology_crat_parsed; 385b5c4e40SEvgeny Pinchuk static struct kfd_system_properties sys_props; 395b5c4e40SEvgeny Pinchuk 405b5c4e40SEvgeny Pinchuk static DECLARE_RWSEM(topology_lock); 415b5c4e40SEvgeny Pinchuk 425b5c4e40SEvgeny Pinchuk struct kfd_dev *kfd_device_by_id(uint32_t gpu_id) 435b5c4e40SEvgeny Pinchuk { 445b5c4e40SEvgeny Pinchuk struct kfd_topology_device *top_dev; 455b5c4e40SEvgeny Pinchuk struct kfd_dev *device = NULL; 465b5c4e40SEvgeny Pinchuk 475b5c4e40SEvgeny Pinchuk down_read(&topology_lock); 485b5c4e40SEvgeny Pinchuk 495b5c4e40SEvgeny Pinchuk list_for_each_entry(top_dev, &topology_device_list, list) 505b5c4e40SEvgeny Pinchuk if (top_dev->gpu_id == gpu_id) { 515b5c4e40SEvgeny Pinchuk device = top_dev->gpu; 525b5c4e40SEvgeny Pinchuk break; 535b5c4e40SEvgeny Pinchuk } 545b5c4e40SEvgeny Pinchuk 555b5c4e40SEvgeny Pinchuk up_read(&topology_lock); 565b5c4e40SEvgeny Pinchuk 575b5c4e40SEvgeny Pinchuk return device; 585b5c4e40SEvgeny Pinchuk } 595b5c4e40SEvgeny Pinchuk 605b5c4e40SEvgeny Pinchuk struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev) 615b5c4e40SEvgeny Pinchuk { 625b5c4e40SEvgeny Pinchuk struct kfd_topology_device *top_dev; 635b5c4e40SEvgeny Pinchuk struct kfd_dev *device = NULL; 645b5c4e40SEvgeny Pinchuk 655b5c4e40SEvgeny Pinchuk down_read(&topology_lock); 665b5c4e40SEvgeny Pinchuk 675b5c4e40SEvgeny Pinchuk list_for_each_entry(top_dev, &topology_device_list, list) 685b5c4e40SEvgeny Pinchuk if (top_dev->gpu->pdev == pdev) { 695b5c4e40SEvgeny Pinchuk device = top_dev->gpu; 705b5c4e40SEvgeny Pinchuk break; 715b5c4e40SEvgeny Pinchuk } 725b5c4e40SEvgeny Pinchuk 735b5c4e40SEvgeny Pinchuk up_read(&topology_lock); 745b5c4e40SEvgeny Pinchuk 755b5c4e40SEvgeny Pinchuk return device; 765b5c4e40SEvgeny Pinchuk } 775b5c4e40SEvgeny Pinchuk 785b5c4e40SEvgeny Pinchuk static int kfd_topology_get_crat_acpi(void *crat_image, size_t *size) 795b5c4e40SEvgeny Pinchuk { 805b5c4e40SEvgeny Pinchuk struct acpi_table_header *crat_table; 815b5c4e40SEvgeny Pinchuk acpi_status status; 825b5c4e40SEvgeny Pinchuk 835b5c4e40SEvgeny Pinchuk if (!size) 845b5c4e40SEvgeny Pinchuk return -EINVAL; 855b5c4e40SEvgeny Pinchuk 865b5c4e40SEvgeny Pinchuk /* 875b5c4e40SEvgeny Pinchuk * Fetch the CRAT table from ACPI 885b5c4e40SEvgeny Pinchuk */ 895b5c4e40SEvgeny Pinchuk status = acpi_get_table(CRAT_SIGNATURE, 0, &crat_table); 905b5c4e40SEvgeny Pinchuk if (status == AE_NOT_FOUND) { 915b5c4e40SEvgeny Pinchuk pr_warn("CRAT table not found\n"); 925b5c4e40SEvgeny Pinchuk return -ENODATA; 935b5c4e40SEvgeny Pinchuk } else if (ACPI_FAILURE(status)) { 945b5c4e40SEvgeny Pinchuk const char *err = acpi_format_exception(status); 955b5c4e40SEvgeny Pinchuk 965b5c4e40SEvgeny Pinchuk pr_err("CRAT table error: %s\n", err); 975b5c4e40SEvgeny Pinchuk return -EINVAL; 985b5c4e40SEvgeny Pinchuk } 995b5c4e40SEvgeny Pinchuk 10016b9201cSOded Gabbay if (*size >= crat_table->length && crat_image != NULL) 1015b5c4e40SEvgeny Pinchuk memcpy(crat_image, crat_table, crat_table->length); 1025b5c4e40SEvgeny Pinchuk 1035b5c4e40SEvgeny Pinchuk *size = crat_table->length; 1045b5c4e40SEvgeny Pinchuk 1055b5c4e40SEvgeny Pinchuk return 0; 1065b5c4e40SEvgeny Pinchuk } 1075b5c4e40SEvgeny Pinchuk 1085b5c4e40SEvgeny Pinchuk static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev, 1095b5c4e40SEvgeny Pinchuk struct crat_subtype_computeunit *cu) 1105b5c4e40SEvgeny Pinchuk { 1115b5c4e40SEvgeny Pinchuk BUG_ON(!dev); 1125b5c4e40SEvgeny Pinchuk BUG_ON(!cu); 1135b5c4e40SEvgeny Pinchuk 1145b5c4e40SEvgeny Pinchuk dev->node_props.cpu_cores_count = cu->num_cpu_cores; 1155b5c4e40SEvgeny Pinchuk dev->node_props.cpu_core_id_base = cu->processor_id_low; 1165b5c4e40SEvgeny Pinchuk if (cu->hsa_capability & CRAT_CU_FLAGS_IOMMU_PRESENT) 1175b5c4e40SEvgeny Pinchuk dev->node_props.capability |= HSA_CAP_ATS_PRESENT; 1185b5c4e40SEvgeny Pinchuk 1195b5c4e40SEvgeny Pinchuk pr_info("CU CPU: cores=%d id_base=%d\n", cu->num_cpu_cores, 1205b5c4e40SEvgeny Pinchuk cu->processor_id_low); 1215b5c4e40SEvgeny Pinchuk } 1225b5c4e40SEvgeny Pinchuk 1235b5c4e40SEvgeny Pinchuk static void kfd_populated_cu_info_gpu(struct kfd_topology_device *dev, 1245b5c4e40SEvgeny Pinchuk struct crat_subtype_computeunit *cu) 1255b5c4e40SEvgeny Pinchuk { 1265b5c4e40SEvgeny Pinchuk BUG_ON(!dev); 1275b5c4e40SEvgeny Pinchuk BUG_ON(!cu); 1285b5c4e40SEvgeny Pinchuk 1295b5c4e40SEvgeny Pinchuk dev->node_props.simd_id_base = cu->processor_id_low; 1305b5c4e40SEvgeny Pinchuk dev->node_props.simd_count = cu->num_simd_cores; 1315b5c4e40SEvgeny Pinchuk dev->node_props.lds_size_in_kb = cu->lds_size_in_kb; 1325b5c4e40SEvgeny Pinchuk dev->node_props.max_waves_per_simd = cu->max_waves_simd; 1335b5c4e40SEvgeny Pinchuk dev->node_props.wave_front_size = cu->wave_front_size; 1345b5c4e40SEvgeny Pinchuk dev->node_props.mem_banks_count = cu->num_banks; 1355b5c4e40SEvgeny Pinchuk dev->node_props.array_count = cu->num_arrays; 1365b5c4e40SEvgeny Pinchuk dev->node_props.cu_per_simd_array = cu->num_cu_per_array; 1375b5c4e40SEvgeny Pinchuk dev->node_props.simd_per_cu = cu->num_simd_per_cu; 1385b5c4e40SEvgeny Pinchuk dev->node_props.max_slots_scratch_cu = cu->max_slots_scatch_cu; 1395b5c4e40SEvgeny Pinchuk if (cu->hsa_capability & CRAT_CU_FLAGS_HOT_PLUGGABLE) 1405b5c4e40SEvgeny Pinchuk dev->node_props.capability |= HSA_CAP_HOT_PLUGGABLE; 1415b5c4e40SEvgeny Pinchuk pr_info("CU GPU: simds=%d id_base=%d\n", cu->num_simd_cores, 1425b5c4e40SEvgeny Pinchuk cu->processor_id_low); 1435b5c4e40SEvgeny Pinchuk } 1445b5c4e40SEvgeny Pinchuk 1455b5c4e40SEvgeny Pinchuk /* kfd_parse_subtype_cu is called when the topology mutex is already acquired */ 1465b5c4e40SEvgeny Pinchuk static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu) 1475b5c4e40SEvgeny Pinchuk { 1485b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 1495b5c4e40SEvgeny Pinchuk int i = 0; 1505b5c4e40SEvgeny Pinchuk 1515b5c4e40SEvgeny Pinchuk BUG_ON(!cu); 1525b5c4e40SEvgeny Pinchuk 1535b5c4e40SEvgeny Pinchuk pr_info("Found CU entry in CRAT table with proximity_domain=%d caps=%x\n", 1545b5c4e40SEvgeny Pinchuk cu->proximity_domain, cu->hsa_capability); 1555b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) { 1565b5c4e40SEvgeny Pinchuk if (cu->proximity_domain == i) { 1575b5c4e40SEvgeny Pinchuk if (cu->flags & CRAT_CU_FLAGS_CPU_PRESENT) 1585b5c4e40SEvgeny Pinchuk kfd_populated_cu_info_cpu(dev, cu); 1595b5c4e40SEvgeny Pinchuk 1605b5c4e40SEvgeny Pinchuk if (cu->flags & CRAT_CU_FLAGS_GPU_PRESENT) 1615b5c4e40SEvgeny Pinchuk kfd_populated_cu_info_gpu(dev, cu); 1625b5c4e40SEvgeny Pinchuk break; 1635b5c4e40SEvgeny Pinchuk } 1645b5c4e40SEvgeny Pinchuk i++; 1655b5c4e40SEvgeny Pinchuk } 1665b5c4e40SEvgeny Pinchuk 1675b5c4e40SEvgeny Pinchuk return 0; 1685b5c4e40SEvgeny Pinchuk } 1695b5c4e40SEvgeny Pinchuk 1705b5c4e40SEvgeny Pinchuk /* 1715b5c4e40SEvgeny Pinchuk * kfd_parse_subtype_mem is called when the topology mutex is 1725b5c4e40SEvgeny Pinchuk * already acquired 1735b5c4e40SEvgeny Pinchuk */ 1745b5c4e40SEvgeny Pinchuk static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem) 1755b5c4e40SEvgeny Pinchuk { 1765b5c4e40SEvgeny Pinchuk struct kfd_mem_properties *props; 1775b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 1785b5c4e40SEvgeny Pinchuk int i = 0; 1795b5c4e40SEvgeny Pinchuk 1805b5c4e40SEvgeny Pinchuk BUG_ON(!mem); 1815b5c4e40SEvgeny Pinchuk 1825b5c4e40SEvgeny Pinchuk pr_info("Found memory entry in CRAT table with proximity_domain=%d\n", 1835b5c4e40SEvgeny Pinchuk mem->promixity_domain); 1845b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) { 1855b5c4e40SEvgeny Pinchuk if (mem->promixity_domain == i) { 1865b5c4e40SEvgeny Pinchuk props = kfd_alloc_struct(props); 18716b9201cSOded Gabbay if (props == NULL) 1885b5c4e40SEvgeny Pinchuk return -ENOMEM; 1895b5c4e40SEvgeny Pinchuk 1905b5c4e40SEvgeny Pinchuk if (dev->node_props.cpu_cores_count == 0) 1915b5c4e40SEvgeny Pinchuk props->heap_type = HSA_MEM_HEAP_TYPE_FB_PRIVATE; 1925b5c4e40SEvgeny Pinchuk else 1935b5c4e40SEvgeny Pinchuk props->heap_type = HSA_MEM_HEAP_TYPE_SYSTEM; 1945b5c4e40SEvgeny Pinchuk 1955b5c4e40SEvgeny Pinchuk if (mem->flags & CRAT_MEM_FLAGS_HOT_PLUGGABLE) 1965b5c4e40SEvgeny Pinchuk props->flags |= HSA_MEM_FLAGS_HOT_PLUGGABLE; 1975b5c4e40SEvgeny Pinchuk if (mem->flags & CRAT_MEM_FLAGS_NON_VOLATILE) 1985b5c4e40SEvgeny Pinchuk props->flags |= HSA_MEM_FLAGS_NON_VOLATILE; 1995b5c4e40SEvgeny Pinchuk 2005b5c4e40SEvgeny Pinchuk props->size_in_bytes = 2015b5c4e40SEvgeny Pinchuk ((uint64_t)mem->length_high << 32) + 2025b5c4e40SEvgeny Pinchuk mem->length_low; 2035b5c4e40SEvgeny Pinchuk props->width = mem->width; 2045b5c4e40SEvgeny Pinchuk 2055b5c4e40SEvgeny Pinchuk dev->mem_bank_count++; 2065b5c4e40SEvgeny Pinchuk list_add_tail(&props->list, &dev->mem_props); 2075b5c4e40SEvgeny Pinchuk 2085b5c4e40SEvgeny Pinchuk break; 2095b5c4e40SEvgeny Pinchuk } 2105b5c4e40SEvgeny Pinchuk i++; 2115b5c4e40SEvgeny Pinchuk } 2125b5c4e40SEvgeny Pinchuk 2135b5c4e40SEvgeny Pinchuk return 0; 2145b5c4e40SEvgeny Pinchuk } 2155b5c4e40SEvgeny Pinchuk 2165b5c4e40SEvgeny Pinchuk /* 2175b5c4e40SEvgeny Pinchuk * kfd_parse_subtype_cache is called when the topology mutex 2185b5c4e40SEvgeny Pinchuk * is already acquired 2195b5c4e40SEvgeny Pinchuk */ 2205b5c4e40SEvgeny Pinchuk static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache) 2215b5c4e40SEvgeny Pinchuk { 2225b5c4e40SEvgeny Pinchuk struct kfd_cache_properties *props; 2235b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 2245b5c4e40SEvgeny Pinchuk uint32_t id; 2255b5c4e40SEvgeny Pinchuk 2265b5c4e40SEvgeny Pinchuk BUG_ON(!cache); 2275b5c4e40SEvgeny Pinchuk 2285b5c4e40SEvgeny Pinchuk id = cache->processor_id_low; 2295b5c4e40SEvgeny Pinchuk 2305b5c4e40SEvgeny Pinchuk pr_info("Found cache entry in CRAT table with processor_id=%d\n", id); 2315b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) 2325b5c4e40SEvgeny Pinchuk if (id == dev->node_props.cpu_core_id_base || 2335b5c4e40SEvgeny Pinchuk id == dev->node_props.simd_id_base) { 2345b5c4e40SEvgeny Pinchuk props = kfd_alloc_struct(props); 23516b9201cSOded Gabbay if (props == NULL) 2365b5c4e40SEvgeny Pinchuk return -ENOMEM; 2375b5c4e40SEvgeny Pinchuk 2385b5c4e40SEvgeny Pinchuk props->processor_id_low = id; 2395b5c4e40SEvgeny Pinchuk props->cache_level = cache->cache_level; 2405b5c4e40SEvgeny Pinchuk props->cache_size = cache->cache_size; 2415b5c4e40SEvgeny Pinchuk props->cacheline_size = cache->cache_line_size; 2425b5c4e40SEvgeny Pinchuk props->cachelines_per_tag = cache->lines_per_tag; 2435b5c4e40SEvgeny Pinchuk props->cache_assoc = cache->associativity; 2445b5c4e40SEvgeny Pinchuk props->cache_latency = cache->cache_latency; 2455b5c4e40SEvgeny Pinchuk 2465b5c4e40SEvgeny Pinchuk if (cache->flags & CRAT_CACHE_FLAGS_DATA_CACHE) 2475b5c4e40SEvgeny Pinchuk props->cache_type |= HSA_CACHE_TYPE_DATA; 2485b5c4e40SEvgeny Pinchuk if (cache->flags & CRAT_CACHE_FLAGS_INST_CACHE) 2495b5c4e40SEvgeny Pinchuk props->cache_type |= HSA_CACHE_TYPE_INSTRUCTION; 2505b5c4e40SEvgeny Pinchuk if (cache->flags & CRAT_CACHE_FLAGS_CPU_CACHE) 2515b5c4e40SEvgeny Pinchuk props->cache_type |= HSA_CACHE_TYPE_CPU; 2525b5c4e40SEvgeny Pinchuk if (cache->flags & CRAT_CACHE_FLAGS_SIMD_CACHE) 2535b5c4e40SEvgeny Pinchuk props->cache_type |= HSA_CACHE_TYPE_HSACU; 2545b5c4e40SEvgeny Pinchuk 2555b5c4e40SEvgeny Pinchuk dev->cache_count++; 2565b5c4e40SEvgeny Pinchuk dev->node_props.caches_count++; 2575b5c4e40SEvgeny Pinchuk list_add_tail(&props->list, &dev->cache_props); 2585b5c4e40SEvgeny Pinchuk 2595b5c4e40SEvgeny Pinchuk break; 2605b5c4e40SEvgeny Pinchuk } 2615b5c4e40SEvgeny Pinchuk 2625b5c4e40SEvgeny Pinchuk return 0; 2635b5c4e40SEvgeny Pinchuk } 2645b5c4e40SEvgeny Pinchuk 2655b5c4e40SEvgeny Pinchuk /* 2665b5c4e40SEvgeny Pinchuk * kfd_parse_subtype_iolink is called when the topology mutex 2675b5c4e40SEvgeny Pinchuk * is already acquired 2685b5c4e40SEvgeny Pinchuk */ 2695b5c4e40SEvgeny Pinchuk static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink) 2705b5c4e40SEvgeny Pinchuk { 2715b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties *props; 2725b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 2735b5c4e40SEvgeny Pinchuk uint32_t i = 0; 2745b5c4e40SEvgeny Pinchuk uint32_t id_from; 2755b5c4e40SEvgeny Pinchuk uint32_t id_to; 2765b5c4e40SEvgeny Pinchuk 2775b5c4e40SEvgeny Pinchuk BUG_ON(!iolink); 2785b5c4e40SEvgeny Pinchuk 2795b5c4e40SEvgeny Pinchuk id_from = iolink->proximity_domain_from; 2805b5c4e40SEvgeny Pinchuk id_to = iolink->proximity_domain_to; 2815b5c4e40SEvgeny Pinchuk 2825b5c4e40SEvgeny Pinchuk pr_info("Found IO link entry in CRAT table with id_from=%d\n", id_from); 2835b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) { 2845b5c4e40SEvgeny Pinchuk if (id_from == i) { 2855b5c4e40SEvgeny Pinchuk props = kfd_alloc_struct(props); 28616b9201cSOded Gabbay if (props == NULL) 2875b5c4e40SEvgeny Pinchuk return -ENOMEM; 2885b5c4e40SEvgeny Pinchuk 2895b5c4e40SEvgeny Pinchuk props->node_from = id_from; 2905b5c4e40SEvgeny Pinchuk props->node_to = id_to; 2915b5c4e40SEvgeny Pinchuk props->ver_maj = iolink->version_major; 2925b5c4e40SEvgeny Pinchuk props->ver_min = iolink->version_minor; 2935b5c4e40SEvgeny Pinchuk 2945b5c4e40SEvgeny Pinchuk /* 2955b5c4e40SEvgeny Pinchuk * weight factor (derived from CDIR), currently always 1 2965b5c4e40SEvgeny Pinchuk */ 2975b5c4e40SEvgeny Pinchuk props->weight = 1; 2985b5c4e40SEvgeny Pinchuk 2995b5c4e40SEvgeny Pinchuk props->min_latency = iolink->minimum_latency; 3005b5c4e40SEvgeny Pinchuk props->max_latency = iolink->maximum_latency; 3015b5c4e40SEvgeny Pinchuk props->min_bandwidth = iolink->minimum_bandwidth_mbs; 3025b5c4e40SEvgeny Pinchuk props->max_bandwidth = iolink->maximum_bandwidth_mbs; 3035b5c4e40SEvgeny Pinchuk props->rec_transfer_size = 3045b5c4e40SEvgeny Pinchuk iolink->recommended_transfer_size; 3055b5c4e40SEvgeny Pinchuk 3065b5c4e40SEvgeny Pinchuk dev->io_link_count++; 3075b5c4e40SEvgeny Pinchuk dev->node_props.io_links_count++; 3085b5c4e40SEvgeny Pinchuk list_add_tail(&props->list, &dev->io_link_props); 3095b5c4e40SEvgeny Pinchuk 3105b5c4e40SEvgeny Pinchuk break; 3115b5c4e40SEvgeny Pinchuk } 3125b5c4e40SEvgeny Pinchuk i++; 3135b5c4e40SEvgeny Pinchuk } 3145b5c4e40SEvgeny Pinchuk 3155b5c4e40SEvgeny Pinchuk return 0; 3165b5c4e40SEvgeny Pinchuk } 3175b5c4e40SEvgeny Pinchuk 3185b5c4e40SEvgeny Pinchuk static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr) 3195b5c4e40SEvgeny Pinchuk { 3205b5c4e40SEvgeny Pinchuk struct crat_subtype_computeunit *cu; 3215b5c4e40SEvgeny Pinchuk struct crat_subtype_memory *mem; 3225b5c4e40SEvgeny Pinchuk struct crat_subtype_cache *cache; 3235b5c4e40SEvgeny Pinchuk struct crat_subtype_iolink *iolink; 3245b5c4e40SEvgeny Pinchuk int ret = 0; 3255b5c4e40SEvgeny Pinchuk 3265b5c4e40SEvgeny Pinchuk BUG_ON(!sub_type_hdr); 3275b5c4e40SEvgeny Pinchuk 3285b5c4e40SEvgeny Pinchuk switch (sub_type_hdr->type) { 3295b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_COMPUTEUNIT_AFFINITY: 3305b5c4e40SEvgeny Pinchuk cu = (struct crat_subtype_computeunit *)sub_type_hdr; 3315b5c4e40SEvgeny Pinchuk ret = kfd_parse_subtype_cu(cu); 3325b5c4e40SEvgeny Pinchuk break; 3335b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_MEMORY_AFFINITY: 3345b5c4e40SEvgeny Pinchuk mem = (struct crat_subtype_memory *)sub_type_hdr; 3355b5c4e40SEvgeny Pinchuk ret = kfd_parse_subtype_mem(mem); 3365b5c4e40SEvgeny Pinchuk break; 3375b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_CACHE_AFFINITY: 3385b5c4e40SEvgeny Pinchuk cache = (struct crat_subtype_cache *)sub_type_hdr; 3395b5c4e40SEvgeny Pinchuk ret = kfd_parse_subtype_cache(cache); 3405b5c4e40SEvgeny Pinchuk break; 3415b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_TLB_AFFINITY: 3425b5c4e40SEvgeny Pinchuk /* 3435b5c4e40SEvgeny Pinchuk * For now, nothing to do here 3445b5c4e40SEvgeny Pinchuk */ 3455b5c4e40SEvgeny Pinchuk pr_info("Found TLB entry in CRAT table (not processing)\n"); 3465b5c4e40SEvgeny Pinchuk break; 3475b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_CCOMPUTE_AFFINITY: 3485b5c4e40SEvgeny Pinchuk /* 3495b5c4e40SEvgeny Pinchuk * For now, nothing to do here 3505b5c4e40SEvgeny Pinchuk */ 3515b5c4e40SEvgeny Pinchuk pr_info("Found CCOMPUTE entry in CRAT table (not processing)\n"); 3525b5c4e40SEvgeny Pinchuk break; 3535b5c4e40SEvgeny Pinchuk case CRAT_SUBTYPE_IOLINK_AFFINITY: 3545b5c4e40SEvgeny Pinchuk iolink = (struct crat_subtype_iolink *)sub_type_hdr; 3555b5c4e40SEvgeny Pinchuk ret = kfd_parse_subtype_iolink(iolink); 3565b5c4e40SEvgeny Pinchuk break; 3575b5c4e40SEvgeny Pinchuk default: 3585b5c4e40SEvgeny Pinchuk pr_warn("Unknown subtype (%d) in CRAT\n", 3595b5c4e40SEvgeny Pinchuk sub_type_hdr->type); 3605b5c4e40SEvgeny Pinchuk } 3615b5c4e40SEvgeny Pinchuk 3625b5c4e40SEvgeny Pinchuk return ret; 3635b5c4e40SEvgeny Pinchuk } 3645b5c4e40SEvgeny Pinchuk 3655b5c4e40SEvgeny Pinchuk static void kfd_release_topology_device(struct kfd_topology_device *dev) 3665b5c4e40SEvgeny Pinchuk { 3675b5c4e40SEvgeny Pinchuk struct kfd_mem_properties *mem; 3685b5c4e40SEvgeny Pinchuk struct kfd_cache_properties *cache; 3695b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties *iolink; 3705b5c4e40SEvgeny Pinchuk 3715b5c4e40SEvgeny Pinchuk BUG_ON(!dev); 3725b5c4e40SEvgeny Pinchuk 3735b5c4e40SEvgeny Pinchuk list_del(&dev->list); 3745b5c4e40SEvgeny Pinchuk 3755b5c4e40SEvgeny Pinchuk while (dev->mem_props.next != &dev->mem_props) { 3765b5c4e40SEvgeny Pinchuk mem = container_of(dev->mem_props.next, 3775b5c4e40SEvgeny Pinchuk struct kfd_mem_properties, list); 3785b5c4e40SEvgeny Pinchuk list_del(&mem->list); 3795b5c4e40SEvgeny Pinchuk kfree(mem); 3805b5c4e40SEvgeny Pinchuk } 3815b5c4e40SEvgeny Pinchuk 3825b5c4e40SEvgeny Pinchuk while (dev->cache_props.next != &dev->cache_props) { 3835b5c4e40SEvgeny Pinchuk cache = container_of(dev->cache_props.next, 3845b5c4e40SEvgeny Pinchuk struct kfd_cache_properties, list); 3855b5c4e40SEvgeny Pinchuk list_del(&cache->list); 3865b5c4e40SEvgeny Pinchuk kfree(cache); 3875b5c4e40SEvgeny Pinchuk } 3885b5c4e40SEvgeny Pinchuk 3895b5c4e40SEvgeny Pinchuk while (dev->io_link_props.next != &dev->io_link_props) { 3905b5c4e40SEvgeny Pinchuk iolink = container_of(dev->io_link_props.next, 3915b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties, list); 3925b5c4e40SEvgeny Pinchuk list_del(&iolink->list); 3935b5c4e40SEvgeny Pinchuk kfree(iolink); 3945b5c4e40SEvgeny Pinchuk } 3955b5c4e40SEvgeny Pinchuk 3965b5c4e40SEvgeny Pinchuk kfree(dev); 3975b5c4e40SEvgeny Pinchuk 3985b5c4e40SEvgeny Pinchuk sys_props.num_devices--; 3995b5c4e40SEvgeny Pinchuk } 4005b5c4e40SEvgeny Pinchuk 4015b5c4e40SEvgeny Pinchuk static void kfd_release_live_view(void) 4025b5c4e40SEvgeny Pinchuk { 4035b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 4045b5c4e40SEvgeny Pinchuk 4055b5c4e40SEvgeny Pinchuk while (topology_device_list.next != &topology_device_list) { 4065b5c4e40SEvgeny Pinchuk dev = container_of(topology_device_list.next, 4075b5c4e40SEvgeny Pinchuk struct kfd_topology_device, list); 4085b5c4e40SEvgeny Pinchuk kfd_release_topology_device(dev); 4095b5c4e40SEvgeny Pinchuk } 4105b5c4e40SEvgeny Pinchuk 4115b5c4e40SEvgeny Pinchuk memset(&sys_props, 0, sizeof(sys_props)); 4125b5c4e40SEvgeny Pinchuk } 4135b5c4e40SEvgeny Pinchuk 4145b5c4e40SEvgeny Pinchuk static struct kfd_topology_device *kfd_create_topology_device(void) 4155b5c4e40SEvgeny Pinchuk { 4165b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 4175b5c4e40SEvgeny Pinchuk 4185b5c4e40SEvgeny Pinchuk dev = kfd_alloc_struct(dev); 41916b9201cSOded Gabbay if (dev == NULL) { 4205b5c4e40SEvgeny Pinchuk pr_err("No memory to allocate a topology device"); 42116b9201cSOded Gabbay return NULL; 4225b5c4e40SEvgeny Pinchuk } 4235b5c4e40SEvgeny Pinchuk 4245b5c4e40SEvgeny Pinchuk INIT_LIST_HEAD(&dev->mem_props); 4255b5c4e40SEvgeny Pinchuk INIT_LIST_HEAD(&dev->cache_props); 4265b5c4e40SEvgeny Pinchuk INIT_LIST_HEAD(&dev->io_link_props); 4275b5c4e40SEvgeny Pinchuk 4285b5c4e40SEvgeny Pinchuk list_add_tail(&dev->list, &topology_device_list); 4295b5c4e40SEvgeny Pinchuk sys_props.num_devices++; 4305b5c4e40SEvgeny Pinchuk 4315b5c4e40SEvgeny Pinchuk return dev; 4325b5c4e40SEvgeny Pinchuk } 4335b5c4e40SEvgeny Pinchuk 4345b5c4e40SEvgeny Pinchuk static int kfd_parse_crat_table(void *crat_image) 4355b5c4e40SEvgeny Pinchuk { 4365b5c4e40SEvgeny Pinchuk struct kfd_topology_device *top_dev; 4375b5c4e40SEvgeny Pinchuk struct crat_subtype_generic *sub_type_hdr; 4385b5c4e40SEvgeny Pinchuk uint16_t node_id; 4395b5c4e40SEvgeny Pinchuk int ret; 4405b5c4e40SEvgeny Pinchuk struct crat_header *crat_table = (struct crat_header *)crat_image; 4415b5c4e40SEvgeny Pinchuk uint16_t num_nodes; 4425b5c4e40SEvgeny Pinchuk uint32_t image_len; 4435b5c4e40SEvgeny Pinchuk 4445b5c4e40SEvgeny Pinchuk if (!crat_image) 4455b5c4e40SEvgeny Pinchuk return -EINVAL; 4465b5c4e40SEvgeny Pinchuk 4475b5c4e40SEvgeny Pinchuk num_nodes = crat_table->num_domains; 4485b5c4e40SEvgeny Pinchuk image_len = crat_table->length; 4495b5c4e40SEvgeny Pinchuk 4505b5c4e40SEvgeny Pinchuk pr_info("Parsing CRAT table with %d nodes\n", num_nodes); 4515b5c4e40SEvgeny Pinchuk 4525b5c4e40SEvgeny Pinchuk for (node_id = 0; node_id < num_nodes; node_id++) { 4535b5c4e40SEvgeny Pinchuk top_dev = kfd_create_topology_device(); 4545b5c4e40SEvgeny Pinchuk if (!top_dev) { 4555b5c4e40SEvgeny Pinchuk kfd_release_live_view(); 4565b5c4e40SEvgeny Pinchuk return -ENOMEM; 4575b5c4e40SEvgeny Pinchuk } 4585b5c4e40SEvgeny Pinchuk } 4595b5c4e40SEvgeny Pinchuk 4605b5c4e40SEvgeny Pinchuk sys_props.platform_id = 4615b5c4e40SEvgeny Pinchuk (*((uint64_t *)crat_table->oem_id)) & CRAT_OEMID_64BIT_MASK; 4625b5c4e40SEvgeny Pinchuk sys_props.platform_oem = *((uint64_t *)crat_table->oem_table_id); 4635b5c4e40SEvgeny Pinchuk sys_props.platform_rev = crat_table->revision; 4645b5c4e40SEvgeny Pinchuk 4655b5c4e40SEvgeny Pinchuk sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1); 4665b5c4e40SEvgeny Pinchuk while ((char *)sub_type_hdr + sizeof(struct crat_subtype_generic) < 4675b5c4e40SEvgeny Pinchuk ((char *)crat_image) + image_len) { 4685b5c4e40SEvgeny Pinchuk if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) { 4695b5c4e40SEvgeny Pinchuk ret = kfd_parse_subtype(sub_type_hdr); 4705b5c4e40SEvgeny Pinchuk if (ret != 0) { 4715b5c4e40SEvgeny Pinchuk kfd_release_live_view(); 4725b5c4e40SEvgeny Pinchuk return ret; 4735b5c4e40SEvgeny Pinchuk } 4745b5c4e40SEvgeny Pinchuk } 4755b5c4e40SEvgeny Pinchuk 4765b5c4e40SEvgeny Pinchuk sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + 4775b5c4e40SEvgeny Pinchuk sub_type_hdr->length); 4785b5c4e40SEvgeny Pinchuk } 4795b5c4e40SEvgeny Pinchuk 4805b5c4e40SEvgeny Pinchuk sys_props.generation_count++; 4815b5c4e40SEvgeny Pinchuk topology_crat_parsed = 1; 4825b5c4e40SEvgeny Pinchuk 4835b5c4e40SEvgeny Pinchuk return 0; 4845b5c4e40SEvgeny Pinchuk } 4855b5c4e40SEvgeny Pinchuk 4865b5c4e40SEvgeny Pinchuk 4875b5c4e40SEvgeny Pinchuk #define sysfs_show_gen_prop(buffer, fmt, ...) \ 4885b5c4e40SEvgeny Pinchuk snprintf(buffer, PAGE_SIZE, "%s"fmt, buffer, __VA_ARGS__) 4895b5c4e40SEvgeny Pinchuk #define sysfs_show_32bit_prop(buffer, name, value) \ 4905b5c4e40SEvgeny Pinchuk sysfs_show_gen_prop(buffer, "%s %u\n", name, value) 4915b5c4e40SEvgeny Pinchuk #define sysfs_show_64bit_prop(buffer, name, value) \ 4925b5c4e40SEvgeny Pinchuk sysfs_show_gen_prop(buffer, "%s %llu\n", name, value) 4935b5c4e40SEvgeny Pinchuk #define sysfs_show_32bit_val(buffer, value) \ 4945b5c4e40SEvgeny Pinchuk sysfs_show_gen_prop(buffer, "%u\n", value) 4955b5c4e40SEvgeny Pinchuk #define sysfs_show_str_val(buffer, value) \ 4965b5c4e40SEvgeny Pinchuk sysfs_show_gen_prop(buffer, "%s\n", value) 4975b5c4e40SEvgeny Pinchuk 4985b5c4e40SEvgeny Pinchuk static ssize_t sysprops_show(struct kobject *kobj, struct attribute *attr, 4995b5c4e40SEvgeny Pinchuk char *buffer) 5005b5c4e40SEvgeny Pinchuk { 5015b5c4e40SEvgeny Pinchuk ssize_t ret; 5025b5c4e40SEvgeny Pinchuk 5035b5c4e40SEvgeny Pinchuk /* Making sure that the buffer is an empty string */ 5045b5c4e40SEvgeny Pinchuk buffer[0] = 0; 5055b5c4e40SEvgeny Pinchuk 5065b5c4e40SEvgeny Pinchuk if (attr == &sys_props.attr_genid) { 5075b5c4e40SEvgeny Pinchuk ret = sysfs_show_32bit_val(buffer, sys_props.generation_count); 5085b5c4e40SEvgeny Pinchuk } else if (attr == &sys_props.attr_props) { 5095b5c4e40SEvgeny Pinchuk sysfs_show_64bit_prop(buffer, "platform_oem", 5105b5c4e40SEvgeny Pinchuk sys_props.platform_oem); 5115b5c4e40SEvgeny Pinchuk sysfs_show_64bit_prop(buffer, "platform_id", 5125b5c4e40SEvgeny Pinchuk sys_props.platform_id); 5135b5c4e40SEvgeny Pinchuk ret = sysfs_show_64bit_prop(buffer, "platform_rev", 5145b5c4e40SEvgeny Pinchuk sys_props.platform_rev); 5155b5c4e40SEvgeny Pinchuk } else { 5165b5c4e40SEvgeny Pinchuk ret = -EINVAL; 5175b5c4e40SEvgeny Pinchuk } 5185b5c4e40SEvgeny Pinchuk 5195b5c4e40SEvgeny Pinchuk return ret; 5205b5c4e40SEvgeny Pinchuk } 5215b5c4e40SEvgeny Pinchuk 5225b5c4e40SEvgeny Pinchuk static const struct sysfs_ops sysprops_ops = { 5235b5c4e40SEvgeny Pinchuk .show = sysprops_show, 5245b5c4e40SEvgeny Pinchuk }; 5255b5c4e40SEvgeny Pinchuk 5265b5c4e40SEvgeny Pinchuk static struct kobj_type sysprops_type = { 5275b5c4e40SEvgeny Pinchuk .sysfs_ops = &sysprops_ops, 5285b5c4e40SEvgeny Pinchuk }; 5295b5c4e40SEvgeny Pinchuk 5305b5c4e40SEvgeny Pinchuk static ssize_t iolink_show(struct kobject *kobj, struct attribute *attr, 5315b5c4e40SEvgeny Pinchuk char *buffer) 5325b5c4e40SEvgeny Pinchuk { 5335b5c4e40SEvgeny Pinchuk ssize_t ret; 5345b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties *iolink; 5355b5c4e40SEvgeny Pinchuk 5365b5c4e40SEvgeny Pinchuk /* Making sure that the buffer is an empty string */ 5375b5c4e40SEvgeny Pinchuk buffer[0] = 0; 5385b5c4e40SEvgeny Pinchuk 5395b5c4e40SEvgeny Pinchuk iolink = container_of(attr, struct kfd_iolink_properties, attr); 5405b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "type", iolink->iolink_type); 5415b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "version_major", iolink->ver_maj); 5425b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "version_minor", iolink->ver_min); 5435b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "node_from", iolink->node_from); 5445b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "node_to", iolink->node_to); 5455b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "weight", iolink->weight); 5465b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "min_latency", iolink->min_latency); 5475b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "max_latency", iolink->max_latency); 5485b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "min_bandwidth", iolink->min_bandwidth); 5495b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "max_bandwidth", iolink->max_bandwidth); 5505b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "recommended_transfer_size", 5515b5c4e40SEvgeny Pinchuk iolink->rec_transfer_size); 5525b5c4e40SEvgeny Pinchuk ret = sysfs_show_32bit_prop(buffer, "flags", iolink->flags); 5535b5c4e40SEvgeny Pinchuk 5545b5c4e40SEvgeny Pinchuk return ret; 5555b5c4e40SEvgeny Pinchuk } 5565b5c4e40SEvgeny Pinchuk 5575b5c4e40SEvgeny Pinchuk static const struct sysfs_ops iolink_ops = { 5585b5c4e40SEvgeny Pinchuk .show = iolink_show, 5595b5c4e40SEvgeny Pinchuk }; 5605b5c4e40SEvgeny Pinchuk 5615b5c4e40SEvgeny Pinchuk static struct kobj_type iolink_type = { 5625b5c4e40SEvgeny Pinchuk .sysfs_ops = &iolink_ops, 5635b5c4e40SEvgeny Pinchuk }; 5645b5c4e40SEvgeny Pinchuk 5655b5c4e40SEvgeny Pinchuk static ssize_t mem_show(struct kobject *kobj, struct attribute *attr, 5665b5c4e40SEvgeny Pinchuk char *buffer) 5675b5c4e40SEvgeny Pinchuk { 5685b5c4e40SEvgeny Pinchuk ssize_t ret; 5695b5c4e40SEvgeny Pinchuk struct kfd_mem_properties *mem; 5705b5c4e40SEvgeny Pinchuk 5715b5c4e40SEvgeny Pinchuk /* Making sure that the buffer is an empty string */ 5725b5c4e40SEvgeny Pinchuk buffer[0] = 0; 5735b5c4e40SEvgeny Pinchuk 5745b5c4e40SEvgeny Pinchuk mem = container_of(attr, struct kfd_mem_properties, attr); 5755b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "heap_type", mem->heap_type); 5765b5c4e40SEvgeny Pinchuk sysfs_show_64bit_prop(buffer, "size_in_bytes", mem->size_in_bytes); 5775b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "flags", mem->flags); 5785b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "width", mem->width); 5795b5c4e40SEvgeny Pinchuk ret = sysfs_show_32bit_prop(buffer, "mem_clk_max", mem->mem_clk_max); 5805b5c4e40SEvgeny Pinchuk 5815b5c4e40SEvgeny Pinchuk return ret; 5825b5c4e40SEvgeny Pinchuk } 5835b5c4e40SEvgeny Pinchuk 5845b5c4e40SEvgeny Pinchuk static const struct sysfs_ops mem_ops = { 5855b5c4e40SEvgeny Pinchuk .show = mem_show, 5865b5c4e40SEvgeny Pinchuk }; 5875b5c4e40SEvgeny Pinchuk 5885b5c4e40SEvgeny Pinchuk static struct kobj_type mem_type = { 5895b5c4e40SEvgeny Pinchuk .sysfs_ops = &mem_ops, 5905b5c4e40SEvgeny Pinchuk }; 5915b5c4e40SEvgeny Pinchuk 5925b5c4e40SEvgeny Pinchuk static ssize_t kfd_cache_show(struct kobject *kobj, struct attribute *attr, 5935b5c4e40SEvgeny Pinchuk char *buffer) 5945b5c4e40SEvgeny Pinchuk { 5955b5c4e40SEvgeny Pinchuk ssize_t ret; 5965b5c4e40SEvgeny Pinchuk uint32_t i; 5975b5c4e40SEvgeny Pinchuk struct kfd_cache_properties *cache; 5985b5c4e40SEvgeny Pinchuk 5995b5c4e40SEvgeny Pinchuk /* Making sure that the buffer is an empty string */ 6005b5c4e40SEvgeny Pinchuk buffer[0] = 0; 6015b5c4e40SEvgeny Pinchuk 6025b5c4e40SEvgeny Pinchuk cache = container_of(attr, struct kfd_cache_properties, attr); 6035b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "processor_id_low", 6045b5c4e40SEvgeny Pinchuk cache->processor_id_low); 6055b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "level", cache->cache_level); 6065b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "size", cache->cache_size); 6075b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "cache_line_size", cache->cacheline_size); 6085b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "cache_lines_per_tag", 6095b5c4e40SEvgeny Pinchuk cache->cachelines_per_tag); 6105b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "association", cache->cache_assoc); 6115b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "latency", cache->cache_latency); 6125b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "type", cache->cache_type); 6135b5c4e40SEvgeny Pinchuk snprintf(buffer, PAGE_SIZE, "%ssibling_map ", buffer); 6145b5c4e40SEvgeny Pinchuk for (i = 0; i < KFD_TOPOLOGY_CPU_SIBLINGS; i++) 6155b5c4e40SEvgeny Pinchuk ret = snprintf(buffer, PAGE_SIZE, "%s%d%s", 6165b5c4e40SEvgeny Pinchuk buffer, cache->sibling_map[i], 6175b5c4e40SEvgeny Pinchuk (i == KFD_TOPOLOGY_CPU_SIBLINGS-1) ? 6185b5c4e40SEvgeny Pinchuk "\n" : ","); 6195b5c4e40SEvgeny Pinchuk 6205b5c4e40SEvgeny Pinchuk return ret; 6215b5c4e40SEvgeny Pinchuk } 6225b5c4e40SEvgeny Pinchuk 6235b5c4e40SEvgeny Pinchuk static const struct sysfs_ops cache_ops = { 6245b5c4e40SEvgeny Pinchuk .show = kfd_cache_show, 6255b5c4e40SEvgeny Pinchuk }; 6265b5c4e40SEvgeny Pinchuk 6275b5c4e40SEvgeny Pinchuk static struct kobj_type cache_type = { 6285b5c4e40SEvgeny Pinchuk .sysfs_ops = &cache_ops, 6295b5c4e40SEvgeny Pinchuk }; 6305b5c4e40SEvgeny Pinchuk 6315b5c4e40SEvgeny Pinchuk static ssize_t node_show(struct kobject *kobj, struct attribute *attr, 6325b5c4e40SEvgeny Pinchuk char *buffer) 6335b5c4e40SEvgeny Pinchuk { 6345b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 6355b5c4e40SEvgeny Pinchuk char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE]; 6365b5c4e40SEvgeny Pinchuk uint32_t i; 637f7c826adSAlexey Skidanov uint32_t log_max_watch_addr; 6385b5c4e40SEvgeny Pinchuk 6395b5c4e40SEvgeny Pinchuk /* Making sure that the buffer is an empty string */ 6405b5c4e40SEvgeny Pinchuk buffer[0] = 0; 6415b5c4e40SEvgeny Pinchuk 6425b5c4e40SEvgeny Pinchuk if (strcmp(attr->name, "gpu_id") == 0) { 6435b5c4e40SEvgeny Pinchuk dev = container_of(attr, struct kfd_topology_device, 6445b5c4e40SEvgeny Pinchuk attr_gpuid); 645f7c826adSAlexey Skidanov return sysfs_show_32bit_val(buffer, dev->gpu_id); 646f7c826adSAlexey Skidanov } 647f7c826adSAlexey Skidanov 648f7c826adSAlexey Skidanov if (strcmp(attr->name, "name") == 0) { 6495b5c4e40SEvgeny Pinchuk dev = container_of(attr, struct kfd_topology_device, 6505b5c4e40SEvgeny Pinchuk attr_name); 6515b5c4e40SEvgeny Pinchuk for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) { 6525b5c4e40SEvgeny Pinchuk public_name[i] = 6535b5c4e40SEvgeny Pinchuk (char)dev->node_props.marketing_name[i]; 6545b5c4e40SEvgeny Pinchuk if (dev->node_props.marketing_name[i] == 0) 6555b5c4e40SEvgeny Pinchuk break; 6565b5c4e40SEvgeny Pinchuk } 6575b5c4e40SEvgeny Pinchuk public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0; 658f7c826adSAlexey Skidanov return sysfs_show_str_val(buffer, public_name); 659f7c826adSAlexey Skidanov } 660f7c826adSAlexey Skidanov 6615b5c4e40SEvgeny Pinchuk dev = container_of(attr, struct kfd_topology_device, 6625b5c4e40SEvgeny Pinchuk attr_props); 6635b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "cpu_cores_count", 6645b5c4e40SEvgeny Pinchuk dev->node_props.cpu_cores_count); 6655b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "simd_count", 6665b5c4e40SEvgeny Pinchuk dev->node_props.simd_count); 6675b5c4e40SEvgeny Pinchuk 6685b5c4e40SEvgeny Pinchuk if (dev->mem_bank_count < dev->node_props.mem_banks_count) { 6690fbbbf8bSOded Gabbay pr_info_once("kfd: mem_banks_count truncated from %d to %d\n", 6705b5c4e40SEvgeny Pinchuk dev->node_props.mem_banks_count, 6715b5c4e40SEvgeny Pinchuk dev->mem_bank_count); 6725b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "mem_banks_count", 6735b5c4e40SEvgeny Pinchuk dev->mem_bank_count); 6745b5c4e40SEvgeny Pinchuk } else { 6755b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "mem_banks_count", 6765b5c4e40SEvgeny Pinchuk dev->node_props.mem_banks_count); 6775b5c4e40SEvgeny Pinchuk } 6785b5c4e40SEvgeny Pinchuk 6795b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "caches_count", 6805b5c4e40SEvgeny Pinchuk dev->node_props.caches_count); 6815b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "io_links_count", 6825b5c4e40SEvgeny Pinchuk dev->node_props.io_links_count); 6835b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "cpu_core_id_base", 6845b5c4e40SEvgeny Pinchuk dev->node_props.cpu_core_id_base); 6855b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "simd_id_base", 6865b5c4e40SEvgeny Pinchuk dev->node_props.simd_id_base); 6875b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "max_waves_per_simd", 6885b5c4e40SEvgeny Pinchuk dev->node_props.max_waves_per_simd); 6895b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "lds_size_in_kb", 6905b5c4e40SEvgeny Pinchuk dev->node_props.lds_size_in_kb); 6915b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "gds_size_in_kb", 6925b5c4e40SEvgeny Pinchuk dev->node_props.gds_size_in_kb); 6935b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "wave_front_size", 6945b5c4e40SEvgeny Pinchuk dev->node_props.wave_front_size); 6955b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "array_count", 6965b5c4e40SEvgeny Pinchuk dev->node_props.array_count); 6975b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine", 6985b5c4e40SEvgeny Pinchuk dev->node_props.simd_arrays_per_engine); 6995b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "cu_per_simd_array", 7005b5c4e40SEvgeny Pinchuk dev->node_props.cu_per_simd_array); 7015b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "simd_per_cu", 7025b5c4e40SEvgeny Pinchuk dev->node_props.simd_per_cu); 7035b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu", 7045b5c4e40SEvgeny Pinchuk dev->node_props.max_slots_scratch_cu); 7055b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "vendor_id", 7065b5c4e40SEvgeny Pinchuk dev->node_props.vendor_id); 7075b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "device_id", 7085b5c4e40SEvgeny Pinchuk dev->node_props.device_id); 7095b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "location_id", 7105b5c4e40SEvgeny Pinchuk dev->node_props.location_id); 7115b5c4e40SEvgeny Pinchuk 7125b5c4e40SEvgeny Pinchuk if (dev->gpu) { 713f7c826adSAlexey Skidanov log_max_watch_addr = 714f7c826adSAlexey Skidanov __ilog2_u32(dev->gpu->device_info->num_of_watch_points); 715f7c826adSAlexey Skidanov 716f7c826adSAlexey Skidanov if (log_max_watch_addr) { 717f7c826adSAlexey Skidanov dev->node_props.capability |= 718f7c826adSAlexey Skidanov HSA_CAP_WATCH_POINTS_SUPPORTED; 719f7c826adSAlexey Skidanov 720f7c826adSAlexey Skidanov dev->node_props.capability |= 721f7c826adSAlexey Skidanov ((log_max_watch_addr << 722f7c826adSAlexey Skidanov HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) & 723f7c826adSAlexey Skidanov HSA_CAP_WATCH_POINTS_TOTALBITS_MASK); 724f7c826adSAlexey Skidanov } 725f7c826adSAlexey Skidanov 7265b5c4e40SEvgeny Pinchuk sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute", 727cea405b1SXihan Zhang dev->gpu->kfd2kgd->get_max_engine_clock_in_mhz( 7285b5c4e40SEvgeny Pinchuk dev->gpu->kgd)); 72942e08c78SOded Gabbay 7305b5c4e40SEvgeny Pinchuk sysfs_show_64bit_prop(buffer, "local_mem_size", 73142e08c78SOded Gabbay (unsigned long long int) 0); 732f1386fbcSOded Gabbay 733f1386fbcSOded Gabbay sysfs_show_32bit_prop(buffer, "fw_version", 734cea405b1SXihan Zhang dev->gpu->kfd2kgd->get_fw_version( 735f1386fbcSOded Gabbay dev->gpu->kgd, 736f1386fbcSOded Gabbay KGD_ENGINE_MEC1)); 737826f5de8SAlexey Skidanov sysfs_show_32bit_prop(buffer, "capability", 738826f5de8SAlexey Skidanov dev->node_props.capability); 7395b5c4e40SEvgeny Pinchuk } 7405b5c4e40SEvgeny Pinchuk 741f7c826adSAlexey Skidanov return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute", 7425b5c4e40SEvgeny Pinchuk cpufreq_quick_get_max(0)/1000); 7435b5c4e40SEvgeny Pinchuk } 7445b5c4e40SEvgeny Pinchuk 7455b5c4e40SEvgeny Pinchuk static const struct sysfs_ops node_ops = { 7465b5c4e40SEvgeny Pinchuk .show = node_show, 7475b5c4e40SEvgeny Pinchuk }; 7485b5c4e40SEvgeny Pinchuk 7495b5c4e40SEvgeny Pinchuk static struct kobj_type node_type = { 7505b5c4e40SEvgeny Pinchuk .sysfs_ops = &node_ops, 7515b5c4e40SEvgeny Pinchuk }; 7525b5c4e40SEvgeny Pinchuk 7535b5c4e40SEvgeny Pinchuk static void kfd_remove_sysfs_file(struct kobject *kobj, struct attribute *attr) 7545b5c4e40SEvgeny Pinchuk { 7555b5c4e40SEvgeny Pinchuk sysfs_remove_file(kobj, attr); 7565b5c4e40SEvgeny Pinchuk kobject_del(kobj); 7575b5c4e40SEvgeny Pinchuk kobject_put(kobj); 7585b5c4e40SEvgeny Pinchuk } 7595b5c4e40SEvgeny Pinchuk 7605b5c4e40SEvgeny Pinchuk static void kfd_remove_sysfs_node_entry(struct kfd_topology_device *dev) 7615b5c4e40SEvgeny Pinchuk { 7625b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties *iolink; 7635b5c4e40SEvgeny Pinchuk struct kfd_cache_properties *cache; 7645b5c4e40SEvgeny Pinchuk struct kfd_mem_properties *mem; 7655b5c4e40SEvgeny Pinchuk 7665b5c4e40SEvgeny Pinchuk BUG_ON(!dev); 7675b5c4e40SEvgeny Pinchuk 7685b5c4e40SEvgeny Pinchuk if (dev->kobj_iolink) { 7695b5c4e40SEvgeny Pinchuk list_for_each_entry(iolink, &dev->io_link_props, list) 7705b5c4e40SEvgeny Pinchuk if (iolink->kobj) { 7715b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_file(iolink->kobj, 7725b5c4e40SEvgeny Pinchuk &iolink->attr); 77316b9201cSOded Gabbay iolink->kobj = NULL; 7745b5c4e40SEvgeny Pinchuk } 7755b5c4e40SEvgeny Pinchuk kobject_del(dev->kobj_iolink); 7765b5c4e40SEvgeny Pinchuk kobject_put(dev->kobj_iolink); 77716b9201cSOded Gabbay dev->kobj_iolink = NULL; 7785b5c4e40SEvgeny Pinchuk } 7795b5c4e40SEvgeny Pinchuk 7805b5c4e40SEvgeny Pinchuk if (dev->kobj_cache) { 7815b5c4e40SEvgeny Pinchuk list_for_each_entry(cache, &dev->cache_props, list) 7825b5c4e40SEvgeny Pinchuk if (cache->kobj) { 7835b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_file(cache->kobj, 7845b5c4e40SEvgeny Pinchuk &cache->attr); 78516b9201cSOded Gabbay cache->kobj = NULL; 7865b5c4e40SEvgeny Pinchuk } 7875b5c4e40SEvgeny Pinchuk kobject_del(dev->kobj_cache); 7885b5c4e40SEvgeny Pinchuk kobject_put(dev->kobj_cache); 78916b9201cSOded Gabbay dev->kobj_cache = NULL; 7905b5c4e40SEvgeny Pinchuk } 7915b5c4e40SEvgeny Pinchuk 7925b5c4e40SEvgeny Pinchuk if (dev->kobj_mem) { 7935b5c4e40SEvgeny Pinchuk list_for_each_entry(mem, &dev->mem_props, list) 7945b5c4e40SEvgeny Pinchuk if (mem->kobj) { 7955b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_file(mem->kobj, &mem->attr); 79616b9201cSOded Gabbay mem->kobj = NULL; 7975b5c4e40SEvgeny Pinchuk } 7985b5c4e40SEvgeny Pinchuk kobject_del(dev->kobj_mem); 7995b5c4e40SEvgeny Pinchuk kobject_put(dev->kobj_mem); 80016b9201cSOded Gabbay dev->kobj_mem = NULL; 8015b5c4e40SEvgeny Pinchuk } 8025b5c4e40SEvgeny Pinchuk 8035b5c4e40SEvgeny Pinchuk if (dev->kobj_node) { 8045b5c4e40SEvgeny Pinchuk sysfs_remove_file(dev->kobj_node, &dev->attr_gpuid); 8055b5c4e40SEvgeny Pinchuk sysfs_remove_file(dev->kobj_node, &dev->attr_name); 8065b5c4e40SEvgeny Pinchuk sysfs_remove_file(dev->kobj_node, &dev->attr_props); 8075b5c4e40SEvgeny Pinchuk kobject_del(dev->kobj_node); 8085b5c4e40SEvgeny Pinchuk kobject_put(dev->kobj_node); 80916b9201cSOded Gabbay dev->kobj_node = NULL; 8105b5c4e40SEvgeny Pinchuk } 8115b5c4e40SEvgeny Pinchuk } 8125b5c4e40SEvgeny Pinchuk 8135b5c4e40SEvgeny Pinchuk static int kfd_build_sysfs_node_entry(struct kfd_topology_device *dev, 8145b5c4e40SEvgeny Pinchuk uint32_t id) 8155b5c4e40SEvgeny Pinchuk { 8165b5c4e40SEvgeny Pinchuk struct kfd_iolink_properties *iolink; 8175b5c4e40SEvgeny Pinchuk struct kfd_cache_properties *cache; 8185b5c4e40SEvgeny Pinchuk struct kfd_mem_properties *mem; 8195b5c4e40SEvgeny Pinchuk int ret; 8205b5c4e40SEvgeny Pinchuk uint32_t i; 8215b5c4e40SEvgeny Pinchuk 8225b5c4e40SEvgeny Pinchuk BUG_ON(!dev); 8235b5c4e40SEvgeny Pinchuk 8245b5c4e40SEvgeny Pinchuk /* 8255b5c4e40SEvgeny Pinchuk * Creating the sysfs folders 8265b5c4e40SEvgeny Pinchuk */ 8275b5c4e40SEvgeny Pinchuk BUG_ON(dev->kobj_node); 8285b5c4e40SEvgeny Pinchuk dev->kobj_node = kfd_alloc_struct(dev->kobj_node); 8295b5c4e40SEvgeny Pinchuk if (!dev->kobj_node) 8305b5c4e40SEvgeny Pinchuk return -ENOMEM; 8315b5c4e40SEvgeny Pinchuk 8325b5c4e40SEvgeny Pinchuk ret = kobject_init_and_add(dev->kobj_node, &node_type, 8335b5c4e40SEvgeny Pinchuk sys_props.kobj_nodes, "%d", id); 8345b5c4e40SEvgeny Pinchuk if (ret < 0) 8355b5c4e40SEvgeny Pinchuk return ret; 8365b5c4e40SEvgeny Pinchuk 8375b5c4e40SEvgeny Pinchuk dev->kobj_mem = kobject_create_and_add("mem_banks", dev->kobj_node); 8385b5c4e40SEvgeny Pinchuk if (!dev->kobj_mem) 8395b5c4e40SEvgeny Pinchuk return -ENOMEM; 8405b5c4e40SEvgeny Pinchuk 8415b5c4e40SEvgeny Pinchuk dev->kobj_cache = kobject_create_and_add("caches", dev->kobj_node); 8425b5c4e40SEvgeny Pinchuk if (!dev->kobj_cache) 8435b5c4e40SEvgeny Pinchuk return -ENOMEM; 8445b5c4e40SEvgeny Pinchuk 8455b5c4e40SEvgeny Pinchuk dev->kobj_iolink = kobject_create_and_add("io_links", dev->kobj_node); 8465b5c4e40SEvgeny Pinchuk if (!dev->kobj_iolink) 8475b5c4e40SEvgeny Pinchuk return -ENOMEM; 8485b5c4e40SEvgeny Pinchuk 8495b5c4e40SEvgeny Pinchuk /* 8505b5c4e40SEvgeny Pinchuk * Creating sysfs files for node properties 8515b5c4e40SEvgeny Pinchuk */ 8525b5c4e40SEvgeny Pinchuk dev->attr_gpuid.name = "gpu_id"; 8535b5c4e40SEvgeny Pinchuk dev->attr_gpuid.mode = KFD_SYSFS_FILE_MODE; 8545b5c4e40SEvgeny Pinchuk sysfs_attr_init(&dev->attr_gpuid); 8555b5c4e40SEvgeny Pinchuk dev->attr_name.name = "name"; 8565b5c4e40SEvgeny Pinchuk dev->attr_name.mode = KFD_SYSFS_FILE_MODE; 8575b5c4e40SEvgeny Pinchuk sysfs_attr_init(&dev->attr_name); 8585b5c4e40SEvgeny Pinchuk dev->attr_props.name = "properties"; 8595b5c4e40SEvgeny Pinchuk dev->attr_props.mode = KFD_SYSFS_FILE_MODE; 8605b5c4e40SEvgeny Pinchuk sysfs_attr_init(&dev->attr_props); 8615b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(dev->kobj_node, &dev->attr_gpuid); 8625b5c4e40SEvgeny Pinchuk if (ret < 0) 8635b5c4e40SEvgeny Pinchuk return ret; 8645b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(dev->kobj_node, &dev->attr_name); 8655b5c4e40SEvgeny Pinchuk if (ret < 0) 8665b5c4e40SEvgeny Pinchuk return ret; 8675b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(dev->kobj_node, &dev->attr_props); 8685b5c4e40SEvgeny Pinchuk if (ret < 0) 8695b5c4e40SEvgeny Pinchuk return ret; 8705b5c4e40SEvgeny Pinchuk 8715b5c4e40SEvgeny Pinchuk i = 0; 8725b5c4e40SEvgeny Pinchuk list_for_each_entry(mem, &dev->mem_props, list) { 8735b5c4e40SEvgeny Pinchuk mem->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 8745b5c4e40SEvgeny Pinchuk if (!mem->kobj) 8755b5c4e40SEvgeny Pinchuk return -ENOMEM; 8765b5c4e40SEvgeny Pinchuk ret = kobject_init_and_add(mem->kobj, &mem_type, 8775b5c4e40SEvgeny Pinchuk dev->kobj_mem, "%d", i); 8785b5c4e40SEvgeny Pinchuk if (ret < 0) 8795b5c4e40SEvgeny Pinchuk return ret; 8805b5c4e40SEvgeny Pinchuk 8815b5c4e40SEvgeny Pinchuk mem->attr.name = "properties"; 8825b5c4e40SEvgeny Pinchuk mem->attr.mode = KFD_SYSFS_FILE_MODE; 8835b5c4e40SEvgeny Pinchuk sysfs_attr_init(&mem->attr); 8845b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(mem->kobj, &mem->attr); 8855b5c4e40SEvgeny Pinchuk if (ret < 0) 8865b5c4e40SEvgeny Pinchuk return ret; 8875b5c4e40SEvgeny Pinchuk i++; 8885b5c4e40SEvgeny Pinchuk } 8895b5c4e40SEvgeny Pinchuk 8905b5c4e40SEvgeny Pinchuk i = 0; 8915b5c4e40SEvgeny Pinchuk list_for_each_entry(cache, &dev->cache_props, list) { 8925b5c4e40SEvgeny Pinchuk cache->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 8935b5c4e40SEvgeny Pinchuk if (!cache->kobj) 8945b5c4e40SEvgeny Pinchuk return -ENOMEM; 8955b5c4e40SEvgeny Pinchuk ret = kobject_init_and_add(cache->kobj, &cache_type, 8965b5c4e40SEvgeny Pinchuk dev->kobj_cache, "%d", i); 8975b5c4e40SEvgeny Pinchuk if (ret < 0) 8985b5c4e40SEvgeny Pinchuk return ret; 8995b5c4e40SEvgeny Pinchuk 9005b5c4e40SEvgeny Pinchuk cache->attr.name = "properties"; 9015b5c4e40SEvgeny Pinchuk cache->attr.mode = KFD_SYSFS_FILE_MODE; 9025b5c4e40SEvgeny Pinchuk sysfs_attr_init(&cache->attr); 9035b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(cache->kobj, &cache->attr); 9045b5c4e40SEvgeny Pinchuk if (ret < 0) 9055b5c4e40SEvgeny Pinchuk return ret; 9065b5c4e40SEvgeny Pinchuk i++; 9075b5c4e40SEvgeny Pinchuk } 9085b5c4e40SEvgeny Pinchuk 9095b5c4e40SEvgeny Pinchuk i = 0; 9105b5c4e40SEvgeny Pinchuk list_for_each_entry(iolink, &dev->io_link_props, list) { 9115b5c4e40SEvgeny Pinchuk iolink->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); 9125b5c4e40SEvgeny Pinchuk if (!iolink->kobj) 9135b5c4e40SEvgeny Pinchuk return -ENOMEM; 9145b5c4e40SEvgeny Pinchuk ret = kobject_init_and_add(iolink->kobj, &iolink_type, 9155b5c4e40SEvgeny Pinchuk dev->kobj_iolink, "%d", i); 9165b5c4e40SEvgeny Pinchuk if (ret < 0) 9175b5c4e40SEvgeny Pinchuk return ret; 9185b5c4e40SEvgeny Pinchuk 9195b5c4e40SEvgeny Pinchuk iolink->attr.name = "properties"; 9205b5c4e40SEvgeny Pinchuk iolink->attr.mode = KFD_SYSFS_FILE_MODE; 9215b5c4e40SEvgeny Pinchuk sysfs_attr_init(&iolink->attr); 9225b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(iolink->kobj, &iolink->attr); 9235b5c4e40SEvgeny Pinchuk if (ret < 0) 9245b5c4e40SEvgeny Pinchuk return ret; 9255b5c4e40SEvgeny Pinchuk i++; 9265b5c4e40SEvgeny Pinchuk } 9275b5c4e40SEvgeny Pinchuk 9285b5c4e40SEvgeny Pinchuk return 0; 9295b5c4e40SEvgeny Pinchuk } 9305b5c4e40SEvgeny Pinchuk 9315b5c4e40SEvgeny Pinchuk static int kfd_build_sysfs_node_tree(void) 9325b5c4e40SEvgeny Pinchuk { 9335b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 9345b5c4e40SEvgeny Pinchuk int ret; 9355b5c4e40SEvgeny Pinchuk uint32_t i = 0; 9365b5c4e40SEvgeny Pinchuk 9375b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) { 9388dfead6cSBen Goz ret = kfd_build_sysfs_node_entry(dev, i); 9395b5c4e40SEvgeny Pinchuk if (ret < 0) 9405b5c4e40SEvgeny Pinchuk return ret; 9415b5c4e40SEvgeny Pinchuk i++; 9425b5c4e40SEvgeny Pinchuk } 9435b5c4e40SEvgeny Pinchuk 9445b5c4e40SEvgeny Pinchuk return 0; 9455b5c4e40SEvgeny Pinchuk } 9465b5c4e40SEvgeny Pinchuk 9475b5c4e40SEvgeny Pinchuk static void kfd_remove_sysfs_node_tree(void) 9485b5c4e40SEvgeny Pinchuk { 9495b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 9505b5c4e40SEvgeny Pinchuk 9515b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) 9525b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_node_entry(dev); 9535b5c4e40SEvgeny Pinchuk } 9545b5c4e40SEvgeny Pinchuk 9555b5c4e40SEvgeny Pinchuk static int kfd_topology_update_sysfs(void) 9565b5c4e40SEvgeny Pinchuk { 9575b5c4e40SEvgeny Pinchuk int ret; 9585b5c4e40SEvgeny Pinchuk 9595b5c4e40SEvgeny Pinchuk pr_info("Creating topology SYSFS entries\n"); 96016b9201cSOded Gabbay if (sys_props.kobj_topology == NULL) { 9615b5c4e40SEvgeny Pinchuk sys_props.kobj_topology = 9625b5c4e40SEvgeny Pinchuk kfd_alloc_struct(sys_props.kobj_topology); 9635b5c4e40SEvgeny Pinchuk if (!sys_props.kobj_topology) 9645b5c4e40SEvgeny Pinchuk return -ENOMEM; 9655b5c4e40SEvgeny Pinchuk 9665b5c4e40SEvgeny Pinchuk ret = kobject_init_and_add(sys_props.kobj_topology, 9675b5c4e40SEvgeny Pinchuk &sysprops_type, &kfd_device->kobj, 9685b5c4e40SEvgeny Pinchuk "topology"); 9695b5c4e40SEvgeny Pinchuk if (ret < 0) 9705b5c4e40SEvgeny Pinchuk return ret; 9715b5c4e40SEvgeny Pinchuk 9725b5c4e40SEvgeny Pinchuk sys_props.kobj_nodes = kobject_create_and_add("nodes", 9735b5c4e40SEvgeny Pinchuk sys_props.kobj_topology); 9745b5c4e40SEvgeny Pinchuk if (!sys_props.kobj_nodes) 9755b5c4e40SEvgeny Pinchuk return -ENOMEM; 9765b5c4e40SEvgeny Pinchuk 9775b5c4e40SEvgeny Pinchuk sys_props.attr_genid.name = "generation_id"; 9785b5c4e40SEvgeny Pinchuk sys_props.attr_genid.mode = KFD_SYSFS_FILE_MODE; 9795b5c4e40SEvgeny Pinchuk sysfs_attr_init(&sys_props.attr_genid); 9805b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(sys_props.kobj_topology, 9815b5c4e40SEvgeny Pinchuk &sys_props.attr_genid); 9825b5c4e40SEvgeny Pinchuk if (ret < 0) 9835b5c4e40SEvgeny Pinchuk return ret; 9845b5c4e40SEvgeny Pinchuk 9855b5c4e40SEvgeny Pinchuk sys_props.attr_props.name = "system_properties"; 9865b5c4e40SEvgeny Pinchuk sys_props.attr_props.mode = KFD_SYSFS_FILE_MODE; 9875b5c4e40SEvgeny Pinchuk sysfs_attr_init(&sys_props.attr_props); 9885b5c4e40SEvgeny Pinchuk ret = sysfs_create_file(sys_props.kobj_topology, 9895b5c4e40SEvgeny Pinchuk &sys_props.attr_props); 9905b5c4e40SEvgeny Pinchuk if (ret < 0) 9915b5c4e40SEvgeny Pinchuk return ret; 9925b5c4e40SEvgeny Pinchuk } 9935b5c4e40SEvgeny Pinchuk 9945b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_node_tree(); 9955b5c4e40SEvgeny Pinchuk 9965b5c4e40SEvgeny Pinchuk return kfd_build_sysfs_node_tree(); 9975b5c4e40SEvgeny Pinchuk } 9985b5c4e40SEvgeny Pinchuk 9995b5c4e40SEvgeny Pinchuk static void kfd_topology_release_sysfs(void) 10005b5c4e40SEvgeny Pinchuk { 10015b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_node_tree(); 10025b5c4e40SEvgeny Pinchuk if (sys_props.kobj_topology) { 10035b5c4e40SEvgeny Pinchuk sysfs_remove_file(sys_props.kobj_topology, 10045b5c4e40SEvgeny Pinchuk &sys_props.attr_genid); 10055b5c4e40SEvgeny Pinchuk sysfs_remove_file(sys_props.kobj_topology, 10065b5c4e40SEvgeny Pinchuk &sys_props.attr_props); 10075b5c4e40SEvgeny Pinchuk if (sys_props.kobj_nodes) { 10085b5c4e40SEvgeny Pinchuk kobject_del(sys_props.kobj_nodes); 10095b5c4e40SEvgeny Pinchuk kobject_put(sys_props.kobj_nodes); 101016b9201cSOded Gabbay sys_props.kobj_nodes = NULL; 10115b5c4e40SEvgeny Pinchuk } 10125b5c4e40SEvgeny Pinchuk kobject_del(sys_props.kobj_topology); 10135b5c4e40SEvgeny Pinchuk kobject_put(sys_props.kobj_topology); 101416b9201cSOded Gabbay sys_props.kobj_topology = NULL; 10155b5c4e40SEvgeny Pinchuk } 10165b5c4e40SEvgeny Pinchuk } 10175b5c4e40SEvgeny Pinchuk 10185b5c4e40SEvgeny Pinchuk int kfd_topology_init(void) 10195b5c4e40SEvgeny Pinchuk { 102016b9201cSOded Gabbay void *crat_image = NULL; 10215b5c4e40SEvgeny Pinchuk size_t image_size = 0; 10225b5c4e40SEvgeny Pinchuk int ret; 10235b5c4e40SEvgeny Pinchuk 10245b5c4e40SEvgeny Pinchuk /* 10255b5c4e40SEvgeny Pinchuk * Initialize the head for the topology device list 10265b5c4e40SEvgeny Pinchuk */ 10275b5c4e40SEvgeny Pinchuk INIT_LIST_HEAD(&topology_device_list); 10285b5c4e40SEvgeny Pinchuk init_rwsem(&topology_lock); 10295b5c4e40SEvgeny Pinchuk topology_crat_parsed = 0; 10305b5c4e40SEvgeny Pinchuk 10315b5c4e40SEvgeny Pinchuk memset(&sys_props, 0, sizeof(sys_props)); 10325b5c4e40SEvgeny Pinchuk 10335b5c4e40SEvgeny Pinchuk /* 10345b5c4e40SEvgeny Pinchuk * Get the CRAT image from the ACPI 10355b5c4e40SEvgeny Pinchuk */ 10365b5c4e40SEvgeny Pinchuk ret = kfd_topology_get_crat_acpi(crat_image, &image_size); 10375b5c4e40SEvgeny Pinchuk if (ret == 0 && image_size > 0) { 10385b5c4e40SEvgeny Pinchuk pr_info("Found CRAT image with size=%zd\n", image_size); 10395b5c4e40SEvgeny Pinchuk crat_image = kmalloc(image_size, GFP_KERNEL); 10405b5c4e40SEvgeny Pinchuk if (!crat_image) { 10415b5c4e40SEvgeny Pinchuk ret = -ENOMEM; 10425b5c4e40SEvgeny Pinchuk pr_err("No memory for allocating CRAT image\n"); 10435b5c4e40SEvgeny Pinchuk goto err; 10445b5c4e40SEvgeny Pinchuk } 10455b5c4e40SEvgeny Pinchuk ret = kfd_topology_get_crat_acpi(crat_image, &image_size); 10465b5c4e40SEvgeny Pinchuk 10475b5c4e40SEvgeny Pinchuk if (ret == 0) { 10485b5c4e40SEvgeny Pinchuk down_write(&topology_lock); 10495b5c4e40SEvgeny Pinchuk ret = kfd_parse_crat_table(crat_image); 10505b5c4e40SEvgeny Pinchuk if (ret == 0) 10515b5c4e40SEvgeny Pinchuk ret = kfd_topology_update_sysfs(); 10525b5c4e40SEvgeny Pinchuk up_write(&topology_lock); 10535b5c4e40SEvgeny Pinchuk } else { 10545b5c4e40SEvgeny Pinchuk pr_err("Couldn't get CRAT table size from ACPI\n"); 10555b5c4e40SEvgeny Pinchuk } 10565b5c4e40SEvgeny Pinchuk kfree(crat_image); 10575b5c4e40SEvgeny Pinchuk } else if (ret == -ENODATA) { 10585b5c4e40SEvgeny Pinchuk ret = 0; 10595b5c4e40SEvgeny Pinchuk } else { 10605b5c4e40SEvgeny Pinchuk pr_err("Couldn't get CRAT table size from ACPI\n"); 10615b5c4e40SEvgeny Pinchuk } 10625b5c4e40SEvgeny Pinchuk 10635b5c4e40SEvgeny Pinchuk err: 10645b5c4e40SEvgeny Pinchuk pr_info("Finished initializing topology ret=%d\n", ret); 10655b5c4e40SEvgeny Pinchuk return ret; 10665b5c4e40SEvgeny Pinchuk } 10675b5c4e40SEvgeny Pinchuk 10685b5c4e40SEvgeny Pinchuk void kfd_topology_shutdown(void) 10695b5c4e40SEvgeny Pinchuk { 10705b5c4e40SEvgeny Pinchuk kfd_topology_release_sysfs(); 10715b5c4e40SEvgeny Pinchuk kfd_release_live_view(); 10725b5c4e40SEvgeny Pinchuk } 10735b5c4e40SEvgeny Pinchuk 10745b5c4e40SEvgeny Pinchuk static void kfd_debug_print_topology(void) 10755b5c4e40SEvgeny Pinchuk { 10765b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 10775b5c4e40SEvgeny Pinchuk uint32_t i = 0; 10785b5c4e40SEvgeny Pinchuk 10795b5c4e40SEvgeny Pinchuk pr_info("DEBUG PRINT OF TOPOLOGY:"); 10805b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) { 10815b5c4e40SEvgeny Pinchuk pr_info("Node: %d\n", i); 10825b5c4e40SEvgeny Pinchuk pr_info("\tGPU assigned: %s\n", (dev->gpu ? "yes" : "no")); 10835b5c4e40SEvgeny Pinchuk pr_info("\tCPU count: %d\n", dev->node_props.cpu_cores_count); 10845b5c4e40SEvgeny Pinchuk pr_info("\tSIMD count: %d", dev->node_props.simd_count); 10855b5c4e40SEvgeny Pinchuk i++; 10865b5c4e40SEvgeny Pinchuk } 10875b5c4e40SEvgeny Pinchuk } 10885b5c4e40SEvgeny Pinchuk 10895b5c4e40SEvgeny Pinchuk static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu) 10905b5c4e40SEvgeny Pinchuk { 10915b5c4e40SEvgeny Pinchuk uint32_t hashout; 10925b5c4e40SEvgeny Pinchuk uint32_t buf[7]; 1093585f0e6cSEdward O'Callaghan uint64_t local_mem_size; 10945b5c4e40SEvgeny Pinchuk int i; 10955b5c4e40SEvgeny Pinchuk 10965b5c4e40SEvgeny Pinchuk if (!gpu) 10975b5c4e40SEvgeny Pinchuk return 0; 10985b5c4e40SEvgeny Pinchuk 1099585f0e6cSEdward O'Callaghan local_mem_size = gpu->kfd2kgd->get_vmem_size(gpu->kgd); 1100585f0e6cSEdward O'Callaghan 11015b5c4e40SEvgeny Pinchuk buf[0] = gpu->pdev->devfn; 11025b5c4e40SEvgeny Pinchuk buf[1] = gpu->pdev->subsystem_vendor; 11035b5c4e40SEvgeny Pinchuk buf[2] = gpu->pdev->subsystem_device; 11045b5c4e40SEvgeny Pinchuk buf[3] = gpu->pdev->device; 11055b5c4e40SEvgeny Pinchuk buf[4] = gpu->pdev->bus->number; 1106585f0e6cSEdward O'Callaghan buf[5] = lower_32_bits(local_mem_size); 1107585f0e6cSEdward O'Callaghan buf[6] = upper_32_bits(local_mem_size); 11085b5c4e40SEvgeny Pinchuk 11095b5c4e40SEvgeny Pinchuk for (i = 0, hashout = 0; i < 7; i++) 11105b5c4e40SEvgeny Pinchuk hashout ^= hash_32(buf[i], KFD_GPU_ID_HASH_WIDTH); 11115b5c4e40SEvgeny Pinchuk 11125b5c4e40SEvgeny Pinchuk return hashout; 11135b5c4e40SEvgeny Pinchuk } 11145b5c4e40SEvgeny Pinchuk 11155b5c4e40SEvgeny Pinchuk static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu) 11165b5c4e40SEvgeny Pinchuk { 11175b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 111816b9201cSOded Gabbay struct kfd_topology_device *out_dev = NULL; 11195b5c4e40SEvgeny Pinchuk 11205b5c4e40SEvgeny Pinchuk BUG_ON(!gpu); 11215b5c4e40SEvgeny Pinchuk 11225b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) 112316b9201cSOded Gabbay if (dev->gpu == NULL && dev->node_props.simd_count > 0) { 11245b5c4e40SEvgeny Pinchuk dev->gpu = gpu; 11255b5c4e40SEvgeny Pinchuk out_dev = dev; 11265b5c4e40SEvgeny Pinchuk break; 11275b5c4e40SEvgeny Pinchuk } 11285b5c4e40SEvgeny Pinchuk 11295b5c4e40SEvgeny Pinchuk return out_dev; 11305b5c4e40SEvgeny Pinchuk } 11315b5c4e40SEvgeny Pinchuk 11325b5c4e40SEvgeny Pinchuk static void kfd_notify_gpu_change(uint32_t gpu_id, int arrival) 11335b5c4e40SEvgeny Pinchuk { 11345b5c4e40SEvgeny Pinchuk /* 11355b5c4e40SEvgeny Pinchuk * TODO: Generate an event for thunk about the arrival/removal 11365b5c4e40SEvgeny Pinchuk * of the GPU 11375b5c4e40SEvgeny Pinchuk */ 11385b5c4e40SEvgeny Pinchuk } 11395b5c4e40SEvgeny Pinchuk 11405b5c4e40SEvgeny Pinchuk int kfd_topology_add_device(struct kfd_dev *gpu) 11415b5c4e40SEvgeny Pinchuk { 11425b5c4e40SEvgeny Pinchuk uint32_t gpu_id; 11435b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 11445b5c4e40SEvgeny Pinchuk int res; 11455b5c4e40SEvgeny Pinchuk 11465b5c4e40SEvgeny Pinchuk BUG_ON(!gpu); 11475b5c4e40SEvgeny Pinchuk 11485b5c4e40SEvgeny Pinchuk gpu_id = kfd_generate_gpu_id(gpu); 11495b5c4e40SEvgeny Pinchuk 11505b5c4e40SEvgeny Pinchuk pr_debug("kfd: Adding new GPU (ID: 0x%x) to topology\n", gpu_id); 11515b5c4e40SEvgeny Pinchuk 11525b5c4e40SEvgeny Pinchuk down_write(&topology_lock); 11535b5c4e40SEvgeny Pinchuk /* 11545b5c4e40SEvgeny Pinchuk * Try to assign the GPU to existing topology device (generated from 11555b5c4e40SEvgeny Pinchuk * CRAT table 11565b5c4e40SEvgeny Pinchuk */ 11575b5c4e40SEvgeny Pinchuk dev = kfd_assign_gpu(gpu); 11585b5c4e40SEvgeny Pinchuk if (!dev) { 11595b5c4e40SEvgeny Pinchuk pr_info("GPU was not found in the current topology. Extending.\n"); 11605b5c4e40SEvgeny Pinchuk kfd_debug_print_topology(); 11615b5c4e40SEvgeny Pinchuk dev = kfd_create_topology_device(); 11625b5c4e40SEvgeny Pinchuk if (!dev) { 11635b5c4e40SEvgeny Pinchuk res = -ENOMEM; 11645b5c4e40SEvgeny Pinchuk goto err; 11655b5c4e40SEvgeny Pinchuk } 11665b5c4e40SEvgeny Pinchuk dev->gpu = gpu; 11675b5c4e40SEvgeny Pinchuk 11685b5c4e40SEvgeny Pinchuk /* 11695b5c4e40SEvgeny Pinchuk * TODO: Make a call to retrieve topology information from the 11705b5c4e40SEvgeny Pinchuk * GPU vBIOS 11715b5c4e40SEvgeny Pinchuk */ 11725b5c4e40SEvgeny Pinchuk 11738eabaf54SKent Russell /* Update the SYSFS tree, since we added another topology 11748eabaf54SKent Russell * device 11755b5c4e40SEvgeny Pinchuk */ 11765b5c4e40SEvgeny Pinchuk if (kfd_topology_update_sysfs() < 0) 11775b5c4e40SEvgeny Pinchuk kfd_topology_release_sysfs(); 11785b5c4e40SEvgeny Pinchuk 11795b5c4e40SEvgeny Pinchuk } 11805b5c4e40SEvgeny Pinchuk 11815b5c4e40SEvgeny Pinchuk dev->gpu_id = gpu_id; 11825b5c4e40SEvgeny Pinchuk gpu->id = gpu_id; 11835b5c4e40SEvgeny Pinchuk dev->node_props.vendor_id = gpu->pdev->vendor; 11845b5c4e40SEvgeny Pinchuk dev->node_props.device_id = gpu->pdev->device; 11855b5c4e40SEvgeny Pinchuk dev->node_props.location_id = (gpu->pdev->bus->number << 24) + 11865b5c4e40SEvgeny Pinchuk (gpu->pdev->devfn & 0xffffff); 11875b5c4e40SEvgeny Pinchuk /* 11885b5c4e40SEvgeny Pinchuk * TODO: Retrieve max engine clock values from KGD 11895b5c4e40SEvgeny Pinchuk */ 11905b5c4e40SEvgeny Pinchuk 11917639a8c4SBen Goz if (dev->gpu->device_info->asic_family == CHIP_CARRIZO) { 11927639a8c4SBen Goz dev->node_props.capability |= HSA_CAP_DOORBELL_PACKET_TYPE; 11937639a8c4SBen Goz pr_info("amdkfd: adding doorbell packet type capability\n"); 11947639a8c4SBen Goz } 11957639a8c4SBen Goz 11965b5c4e40SEvgeny Pinchuk res = 0; 11975b5c4e40SEvgeny Pinchuk 11985b5c4e40SEvgeny Pinchuk err: 11995b5c4e40SEvgeny Pinchuk up_write(&topology_lock); 12005b5c4e40SEvgeny Pinchuk 12015b5c4e40SEvgeny Pinchuk if (res == 0) 12025b5c4e40SEvgeny Pinchuk kfd_notify_gpu_change(gpu_id, 1); 12035b5c4e40SEvgeny Pinchuk 12045b5c4e40SEvgeny Pinchuk return res; 12055b5c4e40SEvgeny Pinchuk } 12065b5c4e40SEvgeny Pinchuk 12075b5c4e40SEvgeny Pinchuk int kfd_topology_remove_device(struct kfd_dev *gpu) 12085b5c4e40SEvgeny Pinchuk { 12095b5c4e40SEvgeny Pinchuk struct kfd_topology_device *dev; 12105b5c4e40SEvgeny Pinchuk uint32_t gpu_id; 12115b5c4e40SEvgeny Pinchuk int res = -ENODEV; 12125b5c4e40SEvgeny Pinchuk 12135b5c4e40SEvgeny Pinchuk BUG_ON(!gpu); 12145b5c4e40SEvgeny Pinchuk 12155b5c4e40SEvgeny Pinchuk down_write(&topology_lock); 12165b5c4e40SEvgeny Pinchuk 12175b5c4e40SEvgeny Pinchuk list_for_each_entry(dev, &topology_device_list, list) 12185b5c4e40SEvgeny Pinchuk if (dev->gpu == gpu) { 12195b5c4e40SEvgeny Pinchuk gpu_id = dev->gpu_id; 12205b5c4e40SEvgeny Pinchuk kfd_remove_sysfs_node_entry(dev); 12215b5c4e40SEvgeny Pinchuk kfd_release_topology_device(dev); 12225b5c4e40SEvgeny Pinchuk res = 0; 12235b5c4e40SEvgeny Pinchuk if (kfd_topology_update_sysfs() < 0) 12245b5c4e40SEvgeny Pinchuk kfd_topology_release_sysfs(); 12255b5c4e40SEvgeny Pinchuk break; 12265b5c4e40SEvgeny Pinchuk } 12275b5c4e40SEvgeny Pinchuk 12285b5c4e40SEvgeny Pinchuk up_write(&topology_lock); 12295b5c4e40SEvgeny Pinchuk 12305b5c4e40SEvgeny Pinchuk if (res == 0) 12315b5c4e40SEvgeny Pinchuk kfd_notify_gpu_change(gpu_id, 0); 12325b5c4e40SEvgeny Pinchuk 12335b5c4e40SEvgeny Pinchuk return res; 12345b5c4e40SEvgeny Pinchuk } 12355b5c4e40SEvgeny Pinchuk 12365b5c4e40SEvgeny Pinchuk /* 12375b5c4e40SEvgeny Pinchuk * When idx is out of bounds, the function will return NULL 12385b5c4e40SEvgeny Pinchuk */ 12395b5c4e40SEvgeny Pinchuk struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx) 12405b5c4e40SEvgeny Pinchuk { 12415b5c4e40SEvgeny Pinchuk 12425b5c4e40SEvgeny Pinchuk struct kfd_topology_device *top_dev; 12435b5c4e40SEvgeny Pinchuk struct kfd_dev *device = NULL; 12445b5c4e40SEvgeny Pinchuk uint8_t device_idx = 0; 12455b5c4e40SEvgeny Pinchuk 12465b5c4e40SEvgeny Pinchuk down_read(&topology_lock); 12475b5c4e40SEvgeny Pinchuk 12485b5c4e40SEvgeny Pinchuk list_for_each_entry(top_dev, &topology_device_list, list) { 12495b5c4e40SEvgeny Pinchuk if (device_idx == idx) { 12505b5c4e40SEvgeny Pinchuk device = top_dev->gpu; 12515b5c4e40SEvgeny Pinchuk break; 12525b5c4e40SEvgeny Pinchuk } 12535b5c4e40SEvgeny Pinchuk 12545b5c4e40SEvgeny Pinchuk device_idx++; 12555b5c4e40SEvgeny Pinchuk } 12565b5c4e40SEvgeny Pinchuk 12575b5c4e40SEvgeny Pinchuk up_read(&topology_lock); 12585b5c4e40SEvgeny Pinchuk 12595b5c4e40SEvgeny Pinchuk return device; 12605b5c4e40SEvgeny Pinchuk 12615b5c4e40SEvgeny Pinchuk } 1262