summaryrefslogtreecommitdiff
path: root/mali_kbase/mali_kbase_reg_track.h
blob: d29999fdcb9a165e574442e12ebd72188fc98711 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
 *
 * (C) COPYRIGHT 2023 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can access it online at
 * http://www.gnu.org/licenses/gpl-2.0.html.
 *
 */
#ifndef _KBASE_REG_TRACK_H_
#define _KBASE_REG_TRACK_H_

#include <linux/types.h>
#include <linux/rbtree.h>

/* Forward declarations of required types. To avoid increasing the compilation
 * times of files that include this header, we want to avoid getting too many
 * transitive dependencies on both custom and kernel headers.
 */
struct kbase_context;
struct kbase_va_region;
struct kbase_device;
struct kmem_cache;

#if MALI_USE_CSF
/* Space for 8 different zones */
#define KBASE_REG_ZONE_BITS 3
#else
/* Space for 4 different zones */
#define KBASE_REG_ZONE_BITS 2
#endif

/**
 * KBASE_REG_ZONE_MAX - Maximum number of GPU memory region zones
 */
#if MALI_USE_CSF
#define KBASE_REG_ZONE_MAX 6ul
#else
#define KBASE_REG_ZONE_MAX 4ul
#endif

/* The bits 11-13 (inclusive) of the kbase_va_region flag are reserved
 * for information about the zone in which it was allocated.
 */
#define KBASE_REG_ZONE_SHIFT (11ul)
#define KBASE_REG_ZONE_MASK (((1 << KBASE_REG_ZONE_BITS) - 1ul) << KBASE_REG_ZONE_SHIFT)

#if KBASE_REG_ZONE_MAX > (1 << KBASE_REG_ZONE_BITS)
#error "Too many zones for the number of zone bits defined"
#endif

#define KBASE_REG_ZONE_CUSTOM_VA_BASE (0x100000000ULL >> PAGE_SHIFT)

#if MALI_USE_CSF
/* only used with 32-bit clients */
/* On a 32bit platform, custom VA should be wired from 4GB to 2^(43).
 */
#define KBASE_REG_ZONE_CUSTOM_VA_SIZE (((1ULL << 43) >> PAGE_SHIFT) - KBASE_REG_ZONE_CUSTOM_VA_BASE)
#else
/* only used with 32-bit clients */
/* On a 32bit platform, custom VA should be wired from 4GB to the VA limit of the
 * GPU. Unfortunately, the Linux mmap() interface limits us to 2^32 pages (2^44
 * bytes, see mmap64 man page for reference).  So we put the default limit to the
 * maximum possible on Linux and shrink it down, if required by the GPU, during
 * initialization.
 */
#define KBASE_REG_ZONE_CUSTOM_VA_SIZE (((1ULL << 44) >> PAGE_SHIFT) - KBASE_REG_ZONE_CUSTOM_VA_BASE)
/* end 32-bit clients only */
#endif

/* The starting address and size of the GPU-executable zone are dynamic
 * and depend on the platform and the number of pages requested by the
 * user process, with an upper limit of 4 GB.
 */
#define KBASE_REG_ZONE_EXEC_VA_MAX_PAGES ((1ULL << 32) >> PAGE_SHIFT) /* 4 GB */
#define KBASE_REG_ZONE_EXEC_VA_SIZE KBASE_REG_ZONE_EXEC_VA_MAX_PAGES

#if MALI_USE_CSF
#define KBASE_REG_ZONE_MCU_SHARED_BASE (0x04000000ULL >> PAGE_SHIFT)
#define MCU_SHARED_ZONE_SIZE (((0x08000000ULL) >> PAGE_SHIFT) - KBASE_REG_ZONE_MCU_SHARED_BASE)

/* For CSF GPUs, the EXEC_VA zone is always 4GB in size, and starts at 2^47 for 64-bit
 * clients, and 2^43 for 32-bit clients.
 */
#define KBASE_REG_ZONE_EXEC_VA_BASE_64 ((1ULL << 47) >> PAGE_SHIFT)
#define KBASE_REG_ZONE_EXEC_VA_BASE_32 ((1ULL << 43) >> PAGE_SHIFT)

/* Executable zone supporting FIXED/FIXABLE allocations.
 * It is always 4GB in size.
 */
#define KBASE_REG_ZONE_EXEC_FIXED_VA_SIZE KBASE_REG_ZONE_EXEC_VA_MAX_PAGES

/* Non-executable zone supporting FIXED/FIXABLE allocations.
 * It extends from (2^47) up to (2^48)-1, for 64-bit userspace clients, and from
 * (2^43) up to (2^44)-1 for 32-bit userspace clients. For the same reason,
 * the end of the FIXED_VA zone for 64-bit clients is (2^48)-1.
 */
#define KBASE_REG_ZONE_FIXED_VA_END_64 ((1ULL << 48) >> PAGE_SHIFT)
#define KBASE_REG_ZONE_FIXED_VA_END_32 ((1ULL << 44) >> PAGE_SHIFT)

#endif

/**
 * enum kbase_memory_zone - Kbase memory zone identifier
 * @SAME_VA_ZONE: Memory zone for allocations where the GPU and CPU VA coincide.
 * @CUSTOM_VA_ZONE: When operating in compatibility mode, this zone is used to
 *                  allow 32-bit userspace (either on a 32-bit device or a
 *                  32-bit application on a 64-bit device) to address the entirety
 *                  of the GPU address space. The @CUSTOM_VA_ZONE is also used
 *                  for JIT allocations: on 64-bit systems, the zone is created
 *                  by reducing the size of the SAME_VA zone by a user-controlled
 *                  amount, whereas on 32-bit systems, it is created as part of
 *                  the existing CUSTOM_VA_ZONE
 * @EXEC_VA_ZONE: Memory zone used to track GPU-executable memory. The start
 *                and end of this zone depend on the individual platform,
 *                and it is initialized upon user process request.
 * @EXEC_FIXED_VA_ZONE: Memory zone used to contain GPU-executable memory
 *                      that also permits FIXED/FIXABLE allocations.
 * @FIXED_VA_ZONE: Memory zone used to allocate memory at userspace-supplied
 *                 addresses.
 * @MCU_SHARED_ZONE: Memory zone created for mappings shared between the MCU
 *                   and Kbase. Currently this is the only zone type that is
 *                   created on a per-device, rather than a per-context
 *                   basis.
 * @MEMORY_ZONE_MAX: Sentinel value used for iterating over all the memory zone
 *                   identifiers.
 * @CONTEXT_ZONE_MAX: Sentinel value used to keep track of the last per-context
 *                    zone for iteration.
 */
enum kbase_memory_zone {
	SAME_VA_ZONE,
	CUSTOM_VA_ZONE,
	EXEC_VA_ZONE,
#if IS_ENABLED(MALI_USE_CSF)
	EXEC_FIXED_VA_ZONE,
	FIXED_VA_ZONE,
	MCU_SHARED_ZONE,
#endif
	MEMORY_ZONE_MAX,
#if IS_ENABLED(MALI_USE_CSF)
	CONTEXT_ZONE_MAX = FIXED_VA_ZONE + 1
#else
	CONTEXT_ZONE_MAX = EXEC_VA_ZONE + 1
#endif
};

/**
 * struct kbase_reg_zone - GPU memory zone information and region tracking
 * @reg_rbtree: RB tree used to track kbase memory regions.
 * @base_pfn: Page Frame Number in GPU virtual address space for the start of
 *            the Zone
 * @va_size_pages: Size of the Zone in pages
 * @id: Memory zone identifier
 * @cache: Pointer to a per-device slab allocator to allow for quickly allocating
 *         new regions
 *
 * Track information about a zone KBASE_REG_ZONE() and related macros.
 * In future, this could also store the &rb_root that are currently in
 * &kbase_context and &kbase_csf_device.
 */
struct kbase_reg_zone {
	struct rb_root reg_rbtree;
	u64 base_pfn;
	u64 va_size_pages;
	enum kbase_memory_zone id;
	struct kmem_cache *cache;
};

/**
 * kbase_zone_to_bits - Convert a memory zone @zone to the corresponding
 *                      bitpattern, for ORing together with other flags.
 * @zone: Memory zone
 *
 * Return: Bitpattern with the appropriate bits set.
 */
unsigned long kbase_zone_to_bits(enum kbase_memory_zone zone);

/**
 * kbase_bits_to_zone - Convert the bitpattern @zone_bits to the corresponding
 *                      zone identifier
 * @zone_bits: Memory allocation flag containing a zone pattern
 *
 * Return: Zone identifier for valid zone bitpatterns,
 */
enum kbase_memory_zone kbase_bits_to_zone(unsigned long zone_bits);

/**
 * kbase_mem_zone_get_name - Get the string name for a given memory zone
 * @zone: Memory zone identifier
 *
 * Return: string for valid memory zone, NULL otherwise
 */
char *kbase_reg_zone_get_name(enum kbase_memory_zone zone);

/**
 * kbase_is_ctx_reg_zone - Determine whether a zone is associated with a
 *                         context or with the device
 * @zone: Zone identifier
 *
 * Return: True if @zone is a context zone, False otherwise
 */
static inline bool kbase_is_ctx_reg_zone(enum kbase_memory_zone zone)
{
#if MALI_USE_CSF
	return !(zone == MCU_SHARED_ZONE);
#else
	return true;
#endif
}

/**
 * kbase_region_tracker_init - Initialize the region tracker data structure
 * @kctx: kbase context
 *
 * Return: 0 if success, negative error code otherwise.
 */
int kbase_region_tracker_init(struct kbase_context *kctx);

/**
 * kbase_region_tracker_init_jit - Initialize the just-in-time memory
 *                                 allocation region
 * @kctx:             Kbase context.
 * @jit_va_pages:     Size of the JIT region in pages.
 * @max_allocations:  Maximum number of allocations allowed for the JIT region.
 *                    Valid range is 0..%BASE_JIT_ALLOC_COUNT.
 * @trim_level:       Trim level for the JIT region.
 *                    Valid range is 0..%BASE_JIT_MAX_TRIM_LEVEL.
 * @group_id:         The physical group ID from which to allocate JIT memory.
 *                    Valid range is 0..(%MEMORY_GROUP_MANAGER_NR_GROUPS-1).
 * @phys_pages_limit: Maximum number of physical pages to use to back the JIT
 *                    region. Must not exceed @jit_va_pages.
 *
 * Return: 0 if success, negative error code otherwise.
 */
int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages, int max_allocations,
				  int trim_level, int group_id, u64 phys_pages_limit);

/**
 * kbase_region_tracker_init_exec - Initialize the GPU-executable memory region
 * @kctx: kbase context
 * @exec_va_pages: Size of the JIT region in pages.
 *                 It must not be greater than 4 GB.
 *
 * Return: 0 if success, negative error code otherwise.
 */
int kbase_region_tracker_init_exec(struct kbase_context *kctx, u64 exec_va_pages);

/**
 * kbase_region_tracker_term - Terminate the JIT region
 * @kctx: kbase context
 */
void kbase_region_tracker_term(struct kbase_context *kctx);

/**
 * kbase_region_tracker_term - Terminate the JIT region
 * @kctx: kbase context
 */
void kbase_region_tracker_term(struct kbase_context *kctx);

/**
 * kbase_region_tracker_find_region_enclosing_address - Find the region containing
 *                                                      a given GPU VA.
 *
 * @kctx: kbase context containing the region
 * @gpu_addr: pointer to check
 *
 * Context: must be called with region lock held.
 *
 * Return: pointer to the valid region on success, NULL otherwise
 *
 */
struct kbase_va_region *
kbase_region_tracker_find_region_enclosing_address(struct kbase_context *kctx, u64 gpu_addr);

/**
 * kbase_region_tracker_find_region_base_address - Check that a pointer is
 *                                                 actually a valid region.
 * @kctx: kbase context containing the region
 * @gpu_addr: pointer to check
 *
 * Must be called with context lock held.
 *
 * Return: pointer to the valid region on success, NULL otherwise
 */
struct kbase_va_region *kbase_region_tracker_find_region_base_address(struct kbase_context *kctx,
								      u64 gpu_addr);

/**
 * kbase_remove_va_region - Remove a region object from the global list.
 *
 * @kbdev: The kbase device
 * @reg: Region object to remove
 *
 * The region reg is removed, possibly by merging with other free and
 * compatible adjacent regions.  It must be called with the context
 * region lock held. The associated memory is not released (see
 * kbase_free_alloced_region). Internal use only.
 */
void kbase_remove_va_region(struct kbase_device *kbdev, struct kbase_va_region *reg);

/**
 * kbase_reg_to_kctx - Obtain the kbase context tracking a VA region.
 * @reg: VA region
 *
 * Return:
 * * pointer to kbase context of the memory allocation
 * * NULL if the region does not belong to a kbase context (for instance,
 *   if the allocation corresponds to a shared MCU region on CSF).
 */
struct kbase_context *kbase_reg_to_kctx(struct kbase_va_region *reg);

struct kbase_va_region *kbase_alloc_free_region(struct kbase_reg_zone *zone, u64 start_pfn,
						size_t nr_pages);

struct kbase_va_region *kbase_ctx_alloc_free_region(struct kbase_context *kctx,
						    enum kbase_memory_zone id, u64 start_pfn,
						    size_t nr_pages);

/**
 * kbase_add_va_region - Add a VA region to the region list for a context.
 *
 * @kctx: kbase context containing the region
 * @reg: the region to add
 * @addr: the address to insert the region at
 * @nr_pages: the number of pages in the region
 * @align: the minimum alignment in pages
 *
 * Return: 0 on success, error code otherwise.
 */
int kbase_add_va_region(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr,
			size_t nr_pages, size_t align);

/**
 * kbase_add_va_region_rbtree - Insert a region into its corresponding rbtree
 *
 * @kbdev: The kbase device
 * @reg: The region to add
 * @addr: The address to add the region at, or 0 to map at any available address
 * @nr_pages: The size of the region in pages
 * @align: The minimum alignment in pages
 *
 * Insert a region into the rbtree that was specified when the region was
 * created. If addr is 0 a free area in the rbtree is used, otherwise the
 * specified address is used.
 *
 * Note that this method should be removed when we get the per-zone locks, as
 * there will be no compelling use-case for manually separating the allocation
 * and the tracking operations.
 *
 * Return: 0 on success, error code otherwise.
 */
int kbase_add_va_region_rbtree(struct kbase_device *kbdev, struct kbase_va_region *reg, u64 addr,
			       size_t nr_pages, size_t align);

/**
 * kbase_free_alloced_region - Free a region object.
 *
 * @reg: VA region
 *
 * The indicated region must be freed of any mapping. Regions with the following
 * flags have special handling:
 * *
 *
 * If the region is not flagged as KBASE_REG_FREE, the region's
 * alloc object will be released.
 * It is a bug if no alloc object exists for non-free regions.
 *
 * If region is MCU_SHARED it is freed.
 */
void kbase_free_alloced_region(struct kbase_va_region *reg);

/**
 * kbase_reg_zone_init - Initialize a zone in @kctx
 * @kbdev: Pointer to kbase device in order to initialize the VA region cache
 * @zone: Memory zone
 * @id: Memory zone identifier to facilitate lookups
 * @base_pfn: Page Frame Number in GPU virtual address space for the start of
 *            the Zone
 * @va_size_pages: Size of the Zone in pages
 *
 * Return:
 * * 0 on success
 * * -ENOMEM on error
 */
int kbase_reg_zone_init(struct kbase_device *kbdev, struct kbase_reg_zone *zone,
			enum kbase_memory_zone id, u64 base_pfn, u64 va_size_pages);

void kbase_reg_zone_term(struct kbase_reg_zone *zone);

/**
 * kbase_ctx_reg_zone_get_nolock - Get a zone from @kctx where the caller does
 *                                 not have @kctx 's region lock
 * @kctx: Pointer to kbase context
 * @zone: Zone identifier
 *
 * This should only be used in performance-critical paths where the code is
 * resilient to a race with the zone changing, and only when the zone is tracked
 * by the @kctx.
 *
 * Return: The zone corresponding to @zone
 */
struct kbase_reg_zone *kbase_ctx_reg_zone_get_nolock(struct kbase_context *kctx,
						     enum kbase_memory_zone zone);

/**
 * kbase_ctx_reg_zone_get - Get a memory zone from @kctx
 * @kctx: Pointer to kbase context
 * @zone: Zone identifier
 *
 * Note that the zone is not refcounted, so there is no corresponding operation to
 * put the zone back.
 *
 * Return: The zone corresponding to @zone
 */
struct kbase_reg_zone *kbase_ctx_reg_zone_get(struct kbase_context *kctx,
					      enum kbase_memory_zone zone);

/**
 * kbase_reg_zone_end_pfn - return the end Page Frame Number of @zone
 * @zone: zone to query
 *
 * Return: The end of the zone corresponding to @zone
 */
static inline u64 kbase_reg_zone_end_pfn(struct kbase_reg_zone *zone)
{
	if (WARN_ON(!zone))
		return 0;

	return zone->base_pfn + zone->va_size_pages;
}

#endif /* _KBASE_REG_TRACK_H_ */