Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2023 Intel Corporation
  4 */
  5
  6#include <drm/drm_print.h>
  7#include <drm/xe_drm.h>
  8#include <linux/kernel.h>
  9#include <linux/slab.h>
 10#include <linux/types.h>
 11
 12#include "xe_bo.h"
 13#include "xe_bo_types.h"
 14#include "xe_device_types.h"
 15#include "xe_drm_client.h"
 16#include "xe_trace.h"
 17
 18/**
 19 * xe_drm_client_alloc() - Allocate drm client
 20 * @void: No arg
 21 *
 22 * Allocate drm client struct to track client memory against
 23 * same till client life. Call this API whenever new client
 24 * has opened xe device.
 25 *
 26 * Return: pointer to client struct or NULL if can't allocate
 27 */
 28struct xe_drm_client *xe_drm_client_alloc(void)
 29{
 30	struct xe_drm_client *client;
 31
 32	client = kzalloc(sizeof(*client), GFP_KERNEL);
 33	if (!client)
 34		return NULL;
 35
 36	kref_init(&client->kref);
 37
 38#ifdef CONFIG_PROC_FS
 39	spin_lock_init(&client->bos_lock);
 40	INIT_LIST_HEAD(&client->bos_list);
 41#endif
 42	return client;
 43}
 44
 45/**
 46 * __xe_drm_client_free() - Free client struct
 47 * @kref: The reference
 48 *
 49 * This frees client struct. Call this API when xe device is closed
 50 * by drm client.
 51 *
 52 * Return: void
 53 */
 54void __xe_drm_client_free(struct kref *kref)
 55{
 56	struct xe_drm_client *client =
 57		container_of(kref, typeof(*client), kref);
 58
 59	kfree(client);
 60}
 61
 62#ifdef CONFIG_PROC_FS
 63/**
 64 * xe_drm_client_add_bo() - Add BO for tracking client mem usage
 65 * @client: The drm client ptr
 66 * @bo: The xe BO ptr
 67 *
 68 * Add all BO created by individual drm client by calling this function.
 69 * This helps in tracking client memory usage.
 70 *
 71 * Return: void
 72 */
 73void xe_drm_client_add_bo(struct xe_drm_client *client,
 74			  struct xe_bo *bo)
 75{
 76	XE_WARN_ON(bo->client);
 77	XE_WARN_ON(!list_empty(&bo->client_link));
 78
 79	spin_lock(&client->bos_lock);
 80	bo->client = xe_drm_client_get(client);
 81	list_add_tail_rcu(&bo->client_link, &client->bos_list);
 82	spin_unlock(&client->bos_lock);
 83}
 84
 85/**
 86 * xe_drm_client_remove_bo() - Remove BO for tracking client mem usage
 87 * @bo: The xe BO ptr
 88 *
 89 * Remove all BO removed by individual drm client by calling this function.
 90 * This helps in tracking client memory usage.
 91 *
 92 * Return: void
 93 */
 94void xe_drm_client_remove_bo(struct xe_bo *bo)
 95{
 96	struct xe_drm_client *client = bo->client;
 97
 98	spin_lock(&client->bos_lock);
 99	list_del_rcu(&bo->client_link);
100	spin_unlock(&client->bos_lock);
101
102	xe_drm_client_put(client);
103}
104
105static void bo_meminfo(struct xe_bo *bo,
106		       struct drm_memory_stats stats[TTM_NUM_MEM_TYPES])
107{
108	u64 sz = bo->size;
109	u32 mem_type;
110
111	if (bo->placement.placement)
112		mem_type = bo->placement.placement->mem_type;
113	else
114		mem_type = XE_PL_TT;
115
116	if (bo->ttm.base.handle_count > 1)
117		stats[mem_type].shared += sz;
118	else
119		stats[mem_type].private += sz;
120
121	if (xe_bo_has_pages(bo)) {
122		stats[mem_type].resident += sz;
123
124		if (!dma_resv_test_signaled(bo->ttm.base.resv,
125					    DMA_RESV_USAGE_BOOKKEEP))
126			stats[mem_type].active += sz;
127		else if (mem_type == XE_PL_SYSTEM)
128			stats[mem_type].purgeable += sz;
129	}
130}
131
132static void show_meminfo(struct drm_printer *p, struct drm_file *file)
133{
134	struct drm_memory_stats stats[TTM_NUM_MEM_TYPES] = {};
135	struct xe_file *xef = file->driver_priv;
136	struct ttm_device *bdev = &xef->xe->ttm;
137	struct ttm_resource_manager *man;
138	struct xe_drm_client *client;
139	struct drm_gem_object *obj;
140	struct xe_bo *bo;
141	unsigned int id;
142	u32 mem_type;
143
144	client = xef->client;
145
146	/* Public objects. */
147	spin_lock(&file->table_lock);
148	idr_for_each_entry(&file->object_idr, obj, id) {
149		struct xe_bo *bo = gem_to_xe_bo(obj);
150
151		bo_meminfo(bo, stats);
152	}
153	spin_unlock(&file->table_lock);
154
155	/* Internal objects. */
156	spin_lock(&client->bos_lock);
157	list_for_each_entry_rcu(bo, &client->bos_list, client_link) {
158		if (!bo || !kref_get_unless_zero(&bo->ttm.base.refcount))
159			continue;
160		bo_meminfo(bo, stats);
161		xe_bo_put(bo);
162	}
163	spin_unlock(&client->bos_lock);
164
165	for (mem_type = XE_PL_SYSTEM; mem_type < TTM_NUM_MEM_TYPES; ++mem_type) {
166		if (!xe_mem_type_to_name[mem_type])
167			continue;
168
169		man = ttm_manager_type(bdev, mem_type);
170
171		if (man) {
172			drm_print_memory_stats(p,
173					       &stats[mem_type],
174					       DRM_GEM_OBJECT_RESIDENT |
175					       (mem_type != XE_PL_SYSTEM ? 0 :
176					       DRM_GEM_OBJECT_PURGEABLE),
177					       xe_mem_type_to_name[mem_type]);
178		}
179	}
180}
181
182/**
183 * xe_drm_client_fdinfo() - Callback for fdinfo interface
184 * @p: The drm_printer ptr
185 * @file: The drm_file ptr
186 *
187 * This is callabck for drm fdinfo interface. Register this callback
188 * in drm driver ops for show_fdinfo.
189 *
190 * Return: void
191 */
192void xe_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file)
193{
194	show_meminfo(p, file);
195}
196#endif