drm/amdkfd: Decouple CRAT parsing from device list update
authorHarish Kasiviswanathan <harish.kasiviswanathan@amd.com>
Sat, 9 Dec 2017 04:08:52 +0000 (23:08 -0500)
committerOded Gabbay <oded.gabbay@gmail.com>
Sat, 9 Dec 2017 04:08:52 +0000 (23:08 -0500)
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 <Harish.Kasiviswanathan@amd.com>
Signed-off-by: Kent Russell <kent.russell@amd.com>
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Reviewed-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
drivers/gpu/drm/amd/amdkfd/kfd_crat.c
drivers/gpu/drm/amd/amdkfd/kfd_crat.h
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.h

index aa754c1..bae91fd 100644 (file)
@@ -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;
 }
 
 /*
index da83105..4e683ae 100644 (file)
@@ -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 */
index 35da4af..f64350b 100644 (file)
@@ -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 @@ err:
 
 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();
index 9996458..0d98b61 100644 (file)
@@ -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__ */