Commit | Line | Data |
---|---|---|
8f965392 TU |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * Copyright © 2023 Intel Corporation | |
4 | */ | |
5 | ||
6 | #include <drm/drm_print.h> | |
08452333 | 7 | #include <drm/xe_drm.h> |
8f965392 TU |
8 | #include <linux/kernel.h> |
9 | #include <linux/slab.h> | |
10 | #include <linux/types.h> | |
11 | ||
08452333 | 12 | #include "xe_bo.h" |
b27970f3 | 13 | #include "xe_bo_types.h" |
8f965392 TU |
14 | #include "xe_device_types.h" |
15 | #include "xe_drm_client.h" | |
b27970f3 | 16 | #include "xe_trace.h" |
8f965392 TU |
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 | */ | |
28 | struct 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 | ||
b27970f3 TU |
38 | #ifdef CONFIG_PROC_FS |
39 | spin_lock_init(&client->bos_lock); | |
40 | INIT_LIST_HEAD(&client->bos_list); | |
41 | #endif | |
8f965392 TU |
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 | */ | |
54 | void __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 | } | |
85c6ad1a TU |
61 | |
62 | #ifdef CONFIG_PROC_FS | |
b27970f3 TU |
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 | */ | |
73 | void 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 | */ | |
94 | void 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 | ||
08452333 TU |
105 | static 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 | ||
61e738d8 | 116 | if (drm_gem_object_is_shared_for_memory_stats(&bo->ttm.base)) |
08452333 TU |
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 | ||
132 | static void show_meminfo(struct drm_printer *p, struct drm_file *file) | |
133 | { | |
08452333 TU |
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) { | |
a0df2cc8 | 166 | if (!xe_mem_type_to_name[mem_type]) |
08452333 TU |
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), | |
a0df2cc8 | 177 | xe_mem_type_to_name[mem_type]); |
08452333 TU |
178 | } |
179 | } | |
180 | } | |
181 | ||
85c6ad1a TU |
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 | */ | |
192 | void xe_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file) | |
193 | { | |
08452333 | 194 | show_meminfo(p, file); |
85c6ad1a TU |
195 | } |
196 | #endif |