1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2020 Intel Corporation 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/slab.h> 8 #include <linux/types.h> 9 10 #include <uapi/drm/i915_drm.h> 11 12 #include <drm/drm_print.h> 13 14 #include "gem/i915_gem_context.h" 15 #include "i915_drm_client.h" 16 #include "i915_file_private.h" 17 #include "i915_gem.h" 18 #include "i915_utils.h" 19 20 void i915_drm_clients_init(struct i915_drm_clients *clients, 21 struct drm_i915_private *i915) 22 { 23 clients->i915 = i915; 24 clients->next_id = 0; 25 26 xa_init_flags(&clients->xarray, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 27 } 28 29 struct i915_drm_client *i915_drm_client_add(struct i915_drm_clients *clients) 30 { 31 struct i915_drm_client *client; 32 struct xarray *xa = &clients->xarray; 33 int ret; 34 35 client = kzalloc(sizeof(*client), GFP_KERNEL); 36 if (!client) 37 return ERR_PTR(-ENOMEM); 38 39 xa_lock_irq(xa); 40 ret = __xa_alloc_cyclic(xa, &client->id, client, xa_limit_32b, 41 &clients->next_id, GFP_KERNEL); 42 xa_unlock_irq(xa); 43 if (ret < 0) 44 goto err; 45 46 kref_init(&client->kref); 47 spin_lock_init(&client->ctx_lock); 48 INIT_LIST_HEAD(&client->ctx_list); 49 client->clients = clients; 50 51 return client; 52 53 err: 54 kfree(client); 55 56 return ERR_PTR(ret); 57 } 58 59 void __i915_drm_client_free(struct kref *kref) 60 { 61 struct i915_drm_client *client = 62 container_of(kref, typeof(*client), kref); 63 struct xarray *xa = &client->clients->xarray; 64 unsigned long flags; 65 66 xa_lock_irqsave(xa, flags); 67 __xa_erase(xa, client->id); 68 xa_unlock_irqrestore(xa, flags); 69 kfree(client); 70 } 71 72 void i915_drm_clients_fini(struct i915_drm_clients *clients) 73 { 74 GEM_BUG_ON(!xa_empty(&clients->xarray)); 75 xa_destroy(&clients->xarray); 76 } 77 78 #ifdef CONFIG_PROC_FS 79 static const char * const uabi_class_names[] = { 80 [I915_ENGINE_CLASS_RENDER] = "render", 81 [I915_ENGINE_CLASS_COPY] = "copy", 82 [I915_ENGINE_CLASS_VIDEO] = "video", 83 [I915_ENGINE_CLASS_VIDEO_ENHANCE] = "video-enhance", 84 [I915_ENGINE_CLASS_COMPUTE] = "compute", 85 }; 86 87 static u64 busy_add(struct i915_gem_context *ctx, unsigned int class) 88 { 89 struct i915_gem_engines_iter it; 90 struct intel_context *ce; 91 u64 total = 0; 92 93 for_each_gem_engine(ce, rcu_dereference(ctx->engines), it) { 94 if (ce->engine->uabi_class != class) 95 continue; 96 97 total += intel_context_get_total_runtime_ns(ce); 98 } 99 100 return total; 101 } 102 103 static void 104 show_client_class(struct seq_file *m, 105 struct i915_drm_client *client, 106 unsigned int class) 107 { 108 const struct list_head *list = &client->ctx_list; 109 u64 total = atomic64_read(&client->past_runtime[class]); 110 const unsigned int capacity = 111 client->clients->i915->engine_uabi_class_count[class]; 112 struct i915_gem_context *ctx; 113 114 rcu_read_lock(); 115 list_for_each_entry_rcu(ctx, list, client_link) 116 total += busy_add(ctx, class); 117 rcu_read_unlock(); 118 119 seq_printf(m, "drm-engine-%s:\t%llu ns\n", 120 uabi_class_names[class], total); 121 122 if (capacity > 1) 123 seq_printf(m, "drm-engine-capacity-%s:\t%u\n", 124 uabi_class_names[class], 125 capacity); 126 } 127 128 void i915_drm_client_fdinfo(struct seq_file *m, struct file *f) 129 { 130 struct drm_file *file = f->private_data; 131 struct drm_i915_file_private *file_priv = file->driver_priv; 132 struct drm_i915_private *i915 = file_priv->dev_priv; 133 struct i915_drm_client *client = file_priv->client; 134 struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 135 unsigned int i; 136 137 /* 138 * ****************************************************************** 139 * For text output format description please see drm-usage-stats.rst! 140 * ****************************************************************** 141 */ 142 143 seq_printf(m, "drm-driver:\t%s\n", i915->drm.driver->name); 144 seq_printf(m, "drm-pdev:\t%04x:%02x:%02x.%d\n", 145 pci_domain_nr(pdev->bus), pdev->bus->number, 146 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 147 seq_printf(m, "drm-client-id:\t%u\n", client->id); 148 149 /* 150 * Temporarily skip showing client engine information with GuC submission till 151 * fetching engine busyness is implemented in the GuC submission backend 152 */ 153 if (GRAPHICS_VER(i915) < 8 || intel_uc_uses_guc_submission(&i915->gt0.uc)) 154 return; 155 156 for (i = 0; i < ARRAY_SIZE(uabi_class_names); i++) 157 show_client_class(m, client, i); 158 } 159 #endif 160