From f9517f06efd717aef12fd23f667c82af472bb084 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Fri, 8 Dec 2017 23:08:52 -0500 Subject: [PATCH 3420/4131] drm/amdkfd: Decouple CRAT parsing from device list update Currently, CRAT parsing is intertwined with topology_device_list and hence repeated calls to kfd_parse_crat_table() will fail. Decouple kfd_parse_crat_table() and topology_device_list. kfd_parse_crat_table() will parse CRAT and add topology devices to a temporary list temp_topology_device_list and then kfd_topology_update_device_list will move contents from temporary list to master list. Signed-off-by: Harish Kasiviswanathan Signed-off-by: Kent Russell Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 118 +++++++++++++++++------------- drivers/gpu/drm/amd/amdkfd/kfd_crat.h | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 84 ++++++++++++++------- drivers/gpu/drm/amd/amdkfd/kfd_topology.h | 6 +- 4 files changed, 132 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index aa754c1..bae91fd 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -23,8 +23,6 @@ #include "kfd_crat.h" #include "kfd_topology.h" -static int topology_crat_parsed; -extern struct list_head topology_device_list; extern struct kfd_system_properties sys_props; static void kfd_populated_cu_info_cpu(struct kfd_topology_device *dev, @@ -57,16 +55,18 @@ static void kfd_populated_cu_info_gpu(struct kfd_topology_device *dev, pr_info("CU GPU: id_base=%d\n", cu->processor_id_low); } -/* kfd_parse_subtype_cu is called when the topology mutex is already acquired */ -static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu) +/* kfd_parse_subtype_cu - parse compute unit subtypes and attach it to correct + * topology device present in the device_list + */ +static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu, + struct list_head *device_list) { struct kfd_topology_device *dev; - int i = 0; pr_info("Found CU entry in CRAT table with proximity_domain=%d caps=%x\n", cu->proximity_domain, cu->hsa_capability); - list_for_each_entry(dev, &topology_device_list, list) { - if (cu->proximity_domain == i) { + list_for_each_entry(dev, device_list, list) { + if (cu->proximity_domain == dev->proximity_domain) { if (cu->flags & CRAT_CU_FLAGS_CPU_PRESENT) kfd_populated_cu_info_cpu(dev, cu); @@ -74,26 +74,24 @@ static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu) kfd_populated_cu_info_gpu(dev, cu); break; } - i++; } return 0; } -/* - * kfd_parse_subtype_mem is called when the topology mutex is - * already acquired +/* kfd_parse_subtype_mem - parse memory subtypes and attach it to correct + * topology device present in the device_list */ -static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem) +static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem, + struct list_head *device_list) { struct kfd_mem_properties *props; struct kfd_topology_device *dev; - int i = 0; pr_info("Found memory entry in CRAT table with proximity_domain=%d\n", mem->proximity_domain); - list_for_each_entry(dev, &topology_device_list, list) { - if (mem->proximity_domain == i) { + list_for_each_entry(dev, device_list, list) { + if (mem->proximity_domain == dev->proximity_domain) { props = kfd_alloc_struct(props); if (!props) return -ENOMEM; @@ -118,17 +116,16 @@ static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem) break; } - i++; } return 0; } -/* - * kfd_parse_subtype_cache is called when the topology mutex - * is already acquired +/* kfd_parse_subtype_cache - parse cache subtypes and attach it to correct + * topology device present in the device_list */ -static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache) +static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache, + struct list_head *device_list) { struct kfd_cache_properties *props; struct kfd_topology_device *dev; @@ -137,7 +134,7 @@ static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache) id = cache->processor_id_low; pr_info("Found cache entry in CRAT table with processor_id=%d\n", id); - list_for_each_entry(dev, &topology_device_list, list) + list_for_each_entry(dev, device_list, list) if (id == dev->node_props.cpu_core_id_base || id == dev->node_props.simd_id_base) { props = kfd_alloc_struct(props); @@ -171,15 +168,14 @@ static int kfd_parse_subtype_cache(struct crat_subtype_cache *cache) return 0; } -/* - * kfd_parse_subtype_iolink is called when the topology mutex - * is already acquired +/* kfd_parse_subtype_iolink - parse iolink subtypes and attach it to correct + * topology device present in the device_list */ -static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink) +static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, + struct list_head *device_list) { struct kfd_iolink_properties *props; struct kfd_topology_device *dev; - uint32_t i = 0; uint32_t id_from; uint32_t id_to; @@ -187,8 +183,8 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink) id_to = iolink->proximity_domain_to; pr_info("Found IO link entry in CRAT table with id_from=%d\n", id_from); - list_for_each_entry(dev, &topology_device_list, list) { - if (id_from == i) { + list_for_each_entry(dev, device_list, list) { + if (id_from == dev->proximity_domain) { props = kfd_alloc_struct(props); if (!props) return -ENOMEM; @@ -216,13 +212,18 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink) break; } - i++; } return 0; } -static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr) +/* kfd_parse_subtype - parse subtypes and attach it to correct topology device + * present in the device_list + * @sub_type_hdr - subtype section of crat_image + * @device_list - list of topology devices present in this crat_image + */ +static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr, + struct list_head *device_list) { struct crat_subtype_computeunit *cu; struct crat_subtype_memory *mem; @@ -233,15 +234,15 @@ static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr) switch (sub_type_hdr->type) { case CRAT_SUBTYPE_COMPUTEUNIT_AFFINITY: cu = (struct crat_subtype_computeunit *)sub_type_hdr; - ret = kfd_parse_subtype_cu(cu); + ret = kfd_parse_subtype_cu(cu, device_list); break; case CRAT_SUBTYPE_MEMORY_AFFINITY: mem = (struct crat_subtype_memory *)sub_type_hdr; - ret = kfd_parse_subtype_mem(mem); + ret = kfd_parse_subtype_mem(mem, device_list); break; case CRAT_SUBTYPE_CACHE_AFFINITY: cache = (struct crat_subtype_cache *)sub_type_hdr; - ret = kfd_parse_subtype_cache(cache); + ret = kfd_parse_subtype_cache(cache, device_list); break; case CRAT_SUBTYPE_TLB_AFFINITY: /* @@ -257,7 +258,7 @@ static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr) break; case CRAT_SUBTYPE_IOLINK_AFFINITY: iolink = (struct crat_subtype_iolink *)sub_type_hdr; - ret = kfd_parse_subtype_iolink(iolink); + ret = kfd_parse_subtype_iolink(iolink, device_list); break; default: pr_warn("Unknown subtype %d in CRAT\n", @@ -267,12 +268,23 @@ static int kfd_parse_subtype(struct crat_subtype_generic *sub_type_hdr) return ret; } -int kfd_parse_crat_table(void *crat_image) +/* kfd_parse_crat_table - parse CRAT table. For each node present in CRAT + * create a kfd_topology_device and add in to device_list. Also parse + * CRAT subtypes and attach it to appropriate kfd_topology_device + * @crat_image - input image containing CRAT + * @device_list - [OUT] list of kfd_topology_device generated after + * parsing crat_image + * @proximity_domain - Proximity domain of the first device in the table + * + * Return - 0 if successful else -ve value + */ +int kfd_parse_crat_table(void *crat_image, struct list_head *device_list, + uint32_t proximity_domain) { struct kfd_topology_device *top_dev; struct crat_subtype_generic *sub_type_hdr; uint16_t node_id; - int ret; + int ret = 0; struct crat_header *crat_table = (struct crat_header *)crat_image; uint16_t num_nodes; uint32_t image_len; @@ -280,17 +292,26 @@ int kfd_parse_crat_table(void *crat_image) if (!crat_image) return -EINVAL; + if (!list_empty(device_list)) { + pr_warn("Error device list should be empty\n"); + return -EINVAL; + } + num_nodes = crat_table->num_domains; image_len = crat_table->length; pr_info("Parsing CRAT table with %d nodes\n", num_nodes); for (node_id = 0; node_id < num_nodes; node_id++) { - top_dev = kfd_create_topology_device(); - if (!top_dev) { - kfd_release_live_view(); - return -ENOMEM; - } + top_dev = kfd_create_topology_device(device_list); + if (!top_dev) + break; + top_dev->proximity_domain = proximity_domain++; + } + + if (!top_dev) { + ret = -ENOMEM; + goto err; } sys_props.platform_id = @@ -302,21 +323,20 @@ int kfd_parse_crat_table(void *crat_image) while ((char *)sub_type_hdr + sizeof(struct crat_subtype_generic) < ((char *)crat_image) + image_len) { if (sub_type_hdr->flags & CRAT_SUBTYPE_FLAGS_ENABLED) { - ret = kfd_parse_subtype(sub_type_hdr); - if (ret != 0) { - kfd_release_live_view(); - return ret; - } + ret = kfd_parse_subtype(sub_type_hdr, device_list); + if (ret) + break; } sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + sub_type_hdr->length); } - sys_props.generation_count++; - topology_crat_parsed = 1; +err: + if (ret) + kfd_release_topology_device_list(device_list); - return 0; + return ret; } /* diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h index da83105..4e683ae 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h @@ -293,6 +293,7 @@ struct cdit_header { int kfd_create_crat_image_acpi(void **crat_image, size_t *size); void kfd_destroy_crat_image(void *crat_image); -int kfd_parse_crat_table(void *crat_image); +int kfd_parse_crat_table(void *crat_image, struct list_head *device_list, + uint32_t proximity_domain); #endif /* KFD_CRAT_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 35da4af..f64350b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -34,7 +34,8 @@ #include "kfd_topology.h" #include "kfd_device_queue_manager.h" -struct list_head topology_device_list; +/* topology_device_list - Master list of all topology devices */ +static struct list_head topology_device_list; struct kfd_system_properties sys_props; static DECLARE_RWSEM(topology_lock); @@ -105,24 +106,27 @@ static void kfd_release_topology_device(struct kfd_topology_device *dev) } kfree(dev); - - sys_props.num_devices--; } -void kfd_release_live_view(void) +void kfd_release_topology_device_list(struct list_head *device_list) { struct kfd_topology_device *dev; - while (topology_device_list.next != &topology_device_list) { - dev = container_of(topology_device_list.next, - struct kfd_topology_device, list); + while (!list_empty(device_list)) { + dev = list_first_entry(device_list, + struct kfd_topology_device, list); kfd_release_topology_device(dev); + } } +static void kfd_release_live_view(void) +{ + kfd_release_topology_device_list(&topology_device_list); memset(&sys_props, 0, sizeof(sys_props)); } -struct kfd_topology_device *kfd_create_topology_device(void) +struct kfd_topology_device *kfd_create_topology_device( + struct list_head *device_list) { struct kfd_topology_device *dev; @@ -136,8 +140,7 @@ struct kfd_topology_device *kfd_create_topology_device(void) INIT_LIST_HEAD(&dev->cache_props); INIT_LIST_HEAD(&dev->io_link_props); - list_add_tail(&dev->list, &topology_device_list); - sys_props.num_devices++; + list_add_tail(&dev->list, device_list); return dev; } @@ -682,16 +685,32 @@ static void kfd_topology_release_sysfs(void) } } +/* Called with write topology_lock acquired */ +static void kfd_topology_update_device_list(struct list_head *temp_list, + struct list_head *master_list) +{ + while (!list_empty(temp_list)) { + list_move_tail(temp_list->next, master_list); + sys_props.num_devices++; + } +} + int kfd_topology_init(void) { void *crat_image = NULL; size_t image_size = 0; int ret; + struct list_head temp_topology_device_list; - /* - * Initialize the head for the topology device list + /* topology_device_list - Master list of all topology devices + * temp_topology_device_list - temporary list created while parsing CRAT + * or VCRAT. Once parsing is complete the contents of list is moved to + * 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)); @@ -701,7 +720,8 @@ int kfd_topology_init(void) */ ret = kfd_create_crat_image_acpi(&crat_image, &image_size); if (!ret) { - ret = kfd_parse_crat_table(crat_image); + ret = kfd_parse_crat_table(crat_image, + &temp_topology_device_list, 0); if (ret) goto err; } else if (ret == -ENODATA) { @@ -714,12 +734,15 @@ int kfd_topology_init(void) } down_write(&topology_lock); + kfd_topology_update_device_list(&temp_topology_device_list, + &topology_device_list); ret = kfd_topology_update_sysfs(); up_write(&topology_lock); - if (!ret) + if (!ret) { + sys_props.generation_count++; pr_info("Finished initializing topology\n"); - else + } else pr_err("Failed to update topology in sysfs ret=%d\n", ret); err: @@ -729,8 +752,10 @@ int kfd_topology_init(void) void kfd_topology_shutdown(void) { + down_write(&topology_lock); kfd_topology_release_sysfs(); kfd_release_live_view(); + up_write(&topology_lock); } static void kfd_debug_print_topology(void) @@ -806,13 +831,15 @@ int kfd_topology_add_device(struct kfd_dev *gpu) uint32_t gpu_id; struct kfd_topology_device *dev; struct kfd_cu_info cu_info; - int res; + int res = 0; + struct list_head temp_topology_device_list; + + INIT_LIST_HEAD(&temp_topology_device_list); gpu_id = kfd_generate_gpu_id(gpu); pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id); - down_write(&topology_lock); /* * Try to assign the GPU to existing topology device (generated from * CRAT table @@ -821,11 +848,12 @@ int kfd_topology_add_device(struct kfd_dev *gpu) if (!dev) { pr_info("GPU was not found in the current topology. Extending.\n"); kfd_debug_print_topology(); - dev = kfd_create_topology_device(); + dev = kfd_create_topology_device(&temp_topology_device_list); if (!dev) { res = -ENOMEM; goto err; } + dev->gpu = gpu; /* @@ -833,12 +861,18 @@ int kfd_topology_add_device(struct kfd_dev *gpu) * GPU vBIOS */ + down_write(&topology_lock); + kfd_topology_update_device_list(&temp_topology_device_list, + &topology_device_list); + /* Update the SYSFS tree, since we added another topology * device */ if (kfd_topology_update_sysfs() < 0) kfd_topology_release_sysfs(); + up_write(&topology_lock); + } dev->gpu_id = gpu_id; @@ -859,30 +893,26 @@ int kfd_topology_add_device(struct kfd_dev *gpu) pr_info("Adding doorbell packet type capability\n"); } - res = 0; - -err: - up_write(&topology_lock); - - if (res == 0) + if (!res) kfd_notify_gpu_change(gpu_id, 1); - +err: return res; } int kfd_topology_remove_device(struct kfd_dev *gpu) { - struct kfd_topology_device *dev; + struct kfd_topology_device *dev, *tmp; uint32_t gpu_id; int res = -ENODEV; down_write(&topology_lock); - list_for_each_entry(dev, &topology_device_list, list) + list_for_each_entry_safe(dev, tmp, &topology_device_list, list) if (dev->gpu == gpu) { gpu_id = dev->gpu_id; kfd_remove_sysfs_node_entry(dev); kfd_release_topology_device(dev); + sys_props.num_devices--; res = 0; if (kfd_topology_update_sysfs() < 0) kfd_topology_release_sysfs(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index 9996458..0d98b61 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -135,6 +135,7 @@ struct kfd_iolink_properties { struct kfd_topology_device { struct list_head list; uint32_t gpu_id; + uint32_t proximity_domain; struct kfd_node_properties node_props; uint32_t mem_bank_count; struct list_head mem_props; @@ -164,7 +165,8 @@ struct kfd_system_properties { struct attribute attr_props; }; -struct kfd_topology_device *kfd_create_topology_device(void); -void kfd_release_live_view(void); +struct kfd_topology_device *kfd_create_topology_device( + struct list_head *device_list); +void kfd_release_topology_device_list(struct list_head *device_list); #endif /* __KFD_TOPOLOGY_H__ */ -- 2.7.4