/* *Creatingthesysfsfolders
*/
dev->kobj_node = kfd_alloc_struct(dev->kobj_node); if (!dev->kobj_node) return -ENOMEM;
ret = kobject_init_and_add(dev->kobj_node, &node_type,
sys_props.kobj_nodes, "%d", id); if (ret < 0) {
kobject_put(dev->kobj_node); return ret;
}
dev->kobj_mem = kobject_create_and_add("mem_banks", dev->kobj_node); if (!dev->kobj_mem) return -ENOMEM;
dev->kobj_cache = kobject_create_and_add("caches", dev->kobj_node); if (!dev->kobj_cache) return -ENOMEM;
dev->kobj_iolink = kobject_create_and_add("io_links", dev->kobj_node); if (!dev->kobj_iolink) return -ENOMEM;
dev->kobj_p2plink = kobject_create_and_add("p2p_links", dev->kobj_node); if (!dev->kobj_p2plink) return -ENOMEM;
dev->kobj_perf = kobject_create_and_add("perf", dev->kobj_node); if (!dev->kobj_perf) return -ENOMEM;
/* *Creatingsysfsfilesfornodeproperties
*/
dev->attr_gpuid.name = "gpu_id";
dev->attr_gpuid.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&dev->attr_gpuid);
dev->attr_name.name = "name";
dev->attr_name.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&dev->attr_name);
dev->attr_props.name = "properties";
dev->attr_props.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&dev->attr_props);
ret = sysfs_create_file(dev->kobj_node, &dev->attr_gpuid); if (ret < 0) return ret;
ret = sysfs_create_file(dev->kobj_node, &dev->attr_name); if (ret < 0) return ret;
ret = sysfs_create_file(dev->kobj_node, &dev->attr_props); if (ret < 0) return ret;
i = 0;
list_for_each_entry(mem, &dev->mem_props, list) {
mem->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (!mem->kobj) return -ENOMEM;
ret = kobject_init_and_add(mem->kobj, &mem_type,
dev->kobj_mem, "%d", i); if (ret < 0) {
kobject_put(mem->kobj); return ret;
}
mem->attr.name = "properties";
mem->attr.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&mem->attr);
ret = sysfs_create_file(mem->kobj, &mem->attr); if (ret < 0) return ret;
i++;
}
i = 0;
list_for_each_entry(cache, &dev->cache_props, list) {
cache->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (!cache->kobj) return -ENOMEM;
ret = kobject_init_and_add(cache->kobj, &cache_type,
dev->kobj_cache, "%d", i); if (ret < 0) {
kobject_put(cache->kobj); return ret;
}
cache->attr.name = "properties";
cache->attr.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&cache->attr);
ret = sysfs_create_file(cache->kobj, &cache->attr); if (ret < 0) return ret;
i++;
}
i = 0;
list_for_each_entry(iolink, &dev->io_link_props, list) {
iolink->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (!iolink->kobj) return -ENOMEM;
ret = kobject_init_and_add(iolink->kobj, &iolink_type,
dev->kobj_iolink, "%d", i); if (ret < 0) {
kobject_put(iolink->kobj); return ret;
}
iolink->attr.name = "properties";
iolink->attr.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&iolink->attr);
ret = sysfs_create_file(iolink->kobj, &iolink->attr); if (ret < 0) return ret;
i++;
}
i = 0;
list_for_each_entry(p2plink, &dev->p2p_link_props, list) {
p2plink->kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (!p2plink->kobj) return -ENOMEM;
ret = kobject_init_and_add(p2plink->kobj, &iolink_type,
dev->kobj_p2plink, "%d", i); if (ret < 0) {
kobject_put(p2plink->kobj); return ret;
}
p2plink->attr.name = "properties";
p2plink->attr.mode = KFD_SYSFS_FILE_MODE;
sysfs_attr_init(&p2plink->attr);
ret = sysfs_create_file(p2plink->kobj, &p2plink->attr); if (ret < 0) return ret;
i++;
}
/* All hardware blocks have the same number of attributes. */
num_attrs = ARRAY_SIZE(perf_attr_iommu);
list_for_each_entry(perf, &dev->perf_props, list) {
perf->attr_group = kzalloc(sizeof(struct kfd_perf_attr)
* num_attrs + sizeof(struct attribute_group),
GFP_KERNEL); if (!perf->attr_group) return -ENOMEM;
attrs = (struct attribute **)(perf->attr_group + 1); if (!strcmp(perf->block_name, "iommu")) { /* Information of IOMMU's num_counters and counter_ids is shown *under/sys/bus/event_source/devices/amd_iommu.Wedon't *duplicatehere.
*/
perf_attr_iommu[0].data = perf->max_concurrent; for (i = 0; i < num_attrs; i++)
attrs[i] = &perf_attr_iommu[i].attr.attr;
}
perf->attr_group->name = perf->block_name;
perf->attr_group->attrs = attrs;
ret = sysfs_create_group(dev->kobj_perf, perf->attr_group); if (ret < 0) return ret;
}
return0;
}
/* Called with write topology lock acquired */ staticint kfd_build_sysfs_node_tree(void)
{ struct kfd_topology_device *dev; int ret;
uint32_t i = 0;
list_for_each_entry(dev, &topology_device_list, list) {
ret = kfd_build_sysfs_node_entry(dev, i); if (ret < 0) return ret;
i++;
}
return0;
}
/* Called with write topology lock acquired */ staticvoid kfd_remove_sysfs_node_tree(void)
{ struct kfd_topology_device *dev;
dev = list_last_entry(&topology_device_list, struct kfd_topology_device, list); if (dev) { if (dev->node_props.cpu_cores_count &&
dev->node_props.simd_count) {
pr_info("Topology: Add APU node [0x%0x:0x%0x]\n",
dev->node_props.device_id,
dev->node_props.vendor_id);
} elseif (dev->node_props.cpu_cores_count)
pr_info("Topology: Add CPU node\n"); elseif (dev->node_props.simd_count)
pr_info("Topology: Add dGPU node [0x%0x:0x%0x]\n",
dev->node_props.device_id,
dev->node_props.vendor_id);
}
up_read(&topology_lock);
}
/* Helper function for intializing platform_xx members of *kfd_system_properties.UsesOEMinfofromthelastCPU/APUnode.
*/ staticvoid kfd_update_system_properties(void)
{ struct kfd_topology_device *dev;
/* kfd_add_non_crat_information - Add information that is not currently *definedinCRATbutisnecessaryforKFDtopology *@dev-topologydevicetowhichadditioninfoisadded
*/ staticvoid kfd_add_non_crat_information(struct kfd_topology_device *kdev)
{ /* Check if CPU only node. */ if (!kdev->gpu) { /* Add system memory information */
dmi_walk(find_system_memory, kdev);
} /* TODO: For GPU node, rearrange code from kfd_topology_add_device */
}
int kfd_topology_init(void)
{ void *crat_image = NULL;
size_t image_size = 0; int ret; struct list_head temp_topology_device_list; int cpu_only_node = 0; struct kfd_topology_device *kdev; int proximity_domain;
/* topology_device_list - Master list of all topology devices *temp_topology_device_list-temporarylistcreatedwhileparsingCRAT *orVCRAT.Onceparsingiscompletethecontentsoflistismovedto *topology_device_list
*/
/* Initialize the head for the both the lists */
INIT_LIST_HEAD(&topology_device_list);
INIT_LIST_HEAD(&temp_topology_device_list);
init_rwsem(&topology_lock);
memset(&sys_props, 0, sizeof(sys_props));
/* Proximity domains in ACPI CRAT tables start counting at *0.ThesameshouldbetrueforvirtualCRATtablescreated *atthisstage.GPUsaddedlaterinkfd_topology_add_device *useacounter.
*/
proximity_domain = 0;
ret = kfd_create_crat_image_virtual(&crat_image, &image_size,
COMPUTE_UNIT_CPU, NULL,
proximity_domain);
cpu_only_node = 1; if (ret) {
pr_err("Error creating VCRAT table for CPU\n"); return ret;
}
ret = kfd_parse_crat_table(crat_image,
&temp_topology_device_list,
proximity_domain); if (ret) {
pr_err("Error parsing VCRAT table for CPU\n"); goto err;
}
down_write(&topology_lock);
kfd_topology_update_device_list(&temp_topology_device_list,
&topology_device_list);
topology_crat_proximity_domain = sys_props.num_devices-1;
ret = kfd_topology_update_sysfs();
up_write(&topology_lock);
if (!ret) {
sys_props.generation_count++;
kfd_update_system_properties();
kfd_debug_print_topology();
} else
pr_err("Failed to update topology in sysfs ret=%d\n", ret);
/* For nodes with GPU, this information gets added *whenGPUisdetected(kfd_topology_add_device).
*/ if (cpu_only_node) { /* Add additional information to CPU only node created above */
down_write(&topology_lock);
kdev = list_first_entry(&topology_device_list, struct kfd_topology_device, list);
up_write(&topology_lock);
kfd_add_non_crat_information(kdev);
}
/* There is a very small possibility when generating a *16(KFD_GPU_ID_HASH_WIDTH)bitvaluefrom8wordbuffer *thatthevaluecouldbe0ornon-unique.So,checkif *itisuniqueandnon-zero.Ifnotuniqueincrementtill *uniqueoneisfound.Incaseofoverflow,restartfrom1
*/
down_read(&topology_lock); do {
is_unique = true; if (!gpu_id)
gpu_id = 1;
list_for_each_entry(dev, &topology_device_list, list) { if (dev->gpu && dev->gpu_id == gpu_id) {
is_unique = false; break;
}
} if (unlikely(!is_unique))
gpu_id = (gpu_id + 1) &
((1 << KFD_GPU_ID_HASH_WIDTH) - 1);
} while (!is_unique);
up_read(&topology_lock);
list_for_each_entry(dev, &topology_device_list, list) { /* Discrete GPUs need their own topology device list *entries.Don'tassignthemtoCPU/APUnodes.
*/ if (dev->node_props.cpu_cores_count) continue;
/* If recommended engine is out of range, need to reset the mask */ if (outbound_link->rec_sdma_eng_id_mask & sdma_eng_id_mask)
outbound_link->rec_sdma_eng_id_mask = xgmi_sdma_eng_id_mask; if (inbound_link->rec_sdma_eng_id_mask & sdma_eng_id_mask)
inbound_link->rec_sdma_eng_id_mask = xgmi_sdma_eng_id_mask;
/* GPU only creates direct links so apply flags setting to all */
list_for_each_entry(link, &dev->io_link_props, list) {
link->flags = CRAT_IOLINK_FLAGS_ENABLED;
kfd_set_iolink_no_atomics(dev, NULL, link);
peer_dev = kfd_topology_device_by_proximity_domain(
link->node_to);
if (!peer_dev) continue;
/* Include the CPU peer in GPU hive if connected over xGMI. */ if (!peer_dev->gpu &&
link->iolink_type == CRAT_IOLINK_TYPE_XGMI) { /* *IftheGPUisnotpartofaGPUhive,useitspci *devicelocationasthehiveIDtobindwiththeCPU.
*/ if (!dev->node_props.hive_id)
dev->node_props.hive_id = pci_dev_id(dev->gpu->adev->pdev);
peer_dev->node_props.hive_id = dev->node_props.hive_id;
}
list_for_each_entry(inbound_link, &peer_dev->io_link_props,
list) { if (inbound_link->node_to != link->node_from) continue;
props->node_from = gpu_node;
props->node_to = i;
kdev->node_props.p2p_links_count++;
list_add_tail(&props->list, &kdev->p2p_link_props);
ret = kfd_build_p2p_node_entry(kdev, props); if (ret < 0) return ret;
/* for small Bar, no CPU --> GPU in-direct links */ if (kfd_dev_is_large_bar(kdev->gpu)) { /* CPU <--> CPU <--> GPU, CPU node*/
props2 = kfd_alloc_struct(props2); if (!props2) return -ENOMEM;
/* CU could be inactive. In case of shared cache find the first active *CU.andincaseofnon-sharedcachecheckiftheCUisinactive.If *inactiveactiveskipit
*/ if (first_active_cu) {
pcache = kfd_alloc_struct(pcache); if (!pcache) return -ENOMEM;
/* Helper function. See kfd_fill_gpu_cache_info for parameter description */ staticint fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, struct kfd_gpu_cache_info *pcache_info, struct amdgpu_cu_info *cu_info, struct amdgpu_gfx_config *gfx_info, int cache_type, unsignedint cu_processor_id, struct kfd_node *knode)
{ unsignedint cu_sibling_map_mask = 0; int first_active_cu; int i, j, k, xcc, start, end; int num_xcc = NUM_XCC(knode->xcc_mask); struct kfd_cache_properties *pcache = NULL; enum amdgpu_memory_partition mode; struct amdgpu_device *adev = knode->adev; bool found = false;
start = ffs(knode->xcc_mask) - 1;
end = start + num_xcc;
/* To find the bitmap in the first active cu in the first *xcc,itisbasedontheassumptionthatevreyxccmust *haveatleastoneactivecu.
*/ for (i = 0; i < gfx_info->max_shader_engines && !found; i++) { for (j = 0; j < gfx_info->max_sh_per_se && !found; j++) { if (cu_info->bitmap[start][i % 4][j % 4]) {
cu_sibling_map_mask =
cu_info->bitmap[start][i % 4][j % 4];
found = true;
}
}
}
/* CU could be inactive. In case of shared cache find the first active *CU.andincaseofnon-sharedcachecheckiftheCUisinactive.If *inactiveactiveskipit
*/ if (first_active_cu) {
pcache = kfd_alloc_struct(pcache); if (!pcache) return -ENOMEM;
/* kfd_fill_cache_non_crat_info - Fill GPU cache info using kfd_gpu_cache_info *tables
*/ staticvoid kfd_fill_cache_non_crat_info(struct kfd_topology_device *dev, struct kfd_node *kdev)
{ struct kfd_gpu_cache_info *pcache_info = NULL; int i, j, k, xcc, start, end; int ct = 0; unsignedint cu_processor_id; int ret; unsignedint num_cu_shared; struct amdgpu_cu_info *cu_info = &kdev->adev->gfx.cu_info; struct amdgpu_gfx_config *gfx_info = &kdev->adev->gfx.config; int gpu_processor_id; struct kfd_cache_properties *props_ext = NULL; int num_of_entries = 0; int num_of_cache_types = 0; struct kfd_gpu_cache_info cache_info[KFD_MAX_CACHE_TYPES];
gpu_processor_id = dev->node_props.simd_id_base;
memset(cache_info, 0, sizeof(cache_info));
pcache_info = cache_info;
num_of_cache_types = kfd_get_gpu_cache_info(kdev, &pcache_info); if (!num_of_cache_types) {
pr_warn("no cache info found\n"); return;
}
/* For each type of cache listed in the kfd_gpu_cache_info table, *gothroughallavailableComputeUnits. *The[i,j,k]loopwill *ifkfd_gpu_cache_info.num_cu_shared=1 *willparsethroughallavailableCU *If(kfd_gpu_cache_info.num_cu_shared!=1) *thenitwillconsideronlyoneCUfrom *thesharedunit
*/
start = ffs(kdev->xcc_mask) - 1;
end = start + NUM_XCC(kdev->xcc_mask);
for (ct = 0; ct < num_of_cache_types; ct++) {
cu_processor_id = gpu_processor_id; if (pcache_info[ct].cache_level == 1) { for (xcc = start; xcc < end; xcc++) { for (i = 0; i < gfx_info->max_shader_engines; i++) { for (j = 0; j < gfx_info->max_sh_per_se; j++) { for (k = 0; k < gfx_info->max_cu_per_sh; k += pcache_info[ct].num_cu_shared) {
ret = fill_in_l1_pcache(&props_ext, pcache_info,
cu_info->bitmap[xcc][i % 4][j + i / 4], ct,
cu_processor_id, k);
if (ret < 0) break;
if (!ret) {
num_of_entries++;
list_add_tail(&props_ext->list, &dev->cache_props);
}
/* Move to next CU block */
num_cu_shared = ((k + pcache_info[ct].num_cu_shared) <=
gfx_info->max_cu_per_sh) ?
pcache_info[ct].num_cu_shared :
(gfx_info->max_cu_per_sh - k);
cu_processor_id += num_cu_shared;
}
}
}
}
} else {
ret = fill_in_l2_l3_pcache(&props_ext, pcache_info,
cu_info, gfx_info, ct, cu_processor_id, kdev);
*dev = kfd_assign_gpu(gpu); if (WARN_ON(!*dev)) {
res = -ENODEV; goto err;
}
/* Fill the cache affinity information here for the GPUs *usingVCRAT
*/
kfd_fill_cache_non_crat_info(*dev, gpu);
/* Update the SYSFS tree, since we added another topology *device
*/
res = kfd_topology_update_sysfs(); if (!res)
sys_props.generation_count++; else
dev_err(gpu->adev->dev, "Failed to update GPU to sysfs topology. res=%d\n",
res);
if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(12, 0, 0))
dev->node_props.capability |=
HSA_CAP_TRAP_DEBUG_PRECISE_ALU_OPERATIONS_SUPPORTED;
}
kfd_topology_set_dbg_firmware_support(dev);
}
int kfd_topology_add_device(struct kfd_node *gpu)
{
uint32_t gpu_id; struct kfd_topology_device *dev; int res = 0; int i; constchar *asic_name = amdgpu_asic_name[gpu->adev->asic_type]; struct amdgpu_gfx_config *gfx_info = &gpu->adev->gfx.config; struct amdgpu_cu_info *cu_info = &gpu->adev->gfx.cu_info;
if (gpu->xcp && !gpu->xcp->ddev) {
dev_warn(gpu->adev->dev, "Won't add GPU to topology since it has no drm node assigned."); return0;
} else {
dev_dbg(gpu->adev->dev, "Adding new GPU to topology\n");
}
/* Check to see if this gpu device exists in the topology_device_list. *Ifso,assignthegputothatdevice, *elsecreateaVirtualCRATforthisgpudeviceandthenparsethat *CRATtocreateanewtopologydevice.Oncecreatedassignthegputo *thattopologydevice
*/
down_write(&topology_lock);
dev = kfd_assign_gpu(gpu); if (!dev)
res = kfd_topology_add_device_locked(gpu, &dev);
up_write(&topology_lock); if (res) return res;
/* TODO: Move the following lines to function *kfd_add_non_crat_information
*/
/* Fill-in additional information that is not available in CRAT but *neededforthetopology
*/ for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1; i++) {
dev->node_props.name[i] = __tolower(asic_name[i]); if (asic_name[i] == '\0') break;
}
dev->node_props.name[i] = '\0';
switch (dev->gpu->adev->asic_type) { case CHIP_KAVERI: case CHIP_HAWAII: case CHIP_TONGA:
dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_PRE_1_0 <<
HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) &
HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); break; case CHIP_CARRIZO: case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: case CHIP_POLARIS12: case CHIP_VEGAM:
pr_debug("Adding doorbell packet type capability\n");
dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_1_0 <<
HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) &
HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); break; default: if (KFD_GC_VERSION(dev->gpu) < IP_VERSION(9, 0, 1))
WARN(1, "Unexpected ASIC family %u",
dev->gpu->adev->asic_type); else
kfd_topology_set_capabilities(dev);
}
/* kfd_numa_node_to_apic_id - Returns the APIC ID of the first logical processor *ofthegivenNUMAnode(numa_node_id) *Return-1onfailure
*/ int kfd_numa_node_to_apic_id(int numa_node_id)
{ if (numa_node_id == -1) {
pr_warn("Invalid NUMA Node. Use online CPU mask\n"); return kfd_cpumask_to_apic_id(cpu_online_mask);
} return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id));
}
#ifdefined(CONFIG_DEBUG_FS)
int kfd_debugfs_hqds_by_device(struct seq_file *m, void *data)
{ struct kfd_topology_device *dev; unsignedint i = 0; int r = 0;
down_read(&topology_lock);
list_for_each_entry(dev, &topology_device_list, list) { if (!dev->gpu) {
i++; continue;
}
seq_printf(m, "Node %u, gpu_id %x:\n", i++, dev->gpu->id);
r = dqm_debugfs_hqds(m, dev->gpu->dqm); if (r) break;
}
up_read(&topology_lock);
return r;
}
int kfd_debugfs_rls_by_device(struct seq_file *m, void *data)
{ struct kfd_topology_device *dev; unsignedint i = 0; int r = 0;
down_read(&topology_lock);
list_for_each_entry(dev, &topology_device_list, list) { if (!dev->gpu) {
i++; continue;
}
seq_printf(m, "Node %u, gpu_id %x:\n", i++, dev->gpu->id);
r = pm_debugfs_runlist(m, &dev->gpu->dqm->packet_mgr); if (r) break;
}
up_read(&topology_lock);
return r;
}
#endif
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet am 2026-10-12)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.