summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imagination/pvr_free_list.h
blob: bfb4f5fc622c9cbc7a5aac86108e39fbe080f23a (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
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/* Copyright (c) 2023 Imagination Technologies Ltd. */

#ifndef PVR_FREE_LIST_H
#define PVR_FREE_LIST_H

#include <linux/compiler_attributes.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/xarray.h>
#include <uapi/drm/pvr_drm.h>

#include "pvr_device.h"

/* Forward declaration from pvr_gem.h. */
struct pvr_fw_object;

/* Forward declaration from pvr_gem.h. */
struct pvr_gem_object;

/* Forward declaration from pvr_hwrt.h. */
struct pvr_hwrt_data;

/**
 * struct pvr_free_list_node - structure representing an allocation in the free
 *                             list
 */
struct pvr_free_list_node {
	/** @node: List node for &pvr_free_list.mem_block_list. */
	struct list_head node;

	/** @free_list: Pointer to owning free list. */
	struct pvr_free_list *free_list;

	/** @num_pages: Number of pages in this node. */
	u32 num_pages;

	/** @mem_obj: GEM object representing the pages in this node. */
	struct pvr_gem_object *mem_obj;
};

/**
 * struct pvr_free_list - structure representing a free list
 */
struct pvr_free_list {
	/** @ref_count: Reference count of object. */
	struct kref ref_count;

	/** @pvr_dev: Pointer to device that owns this object. */
	struct pvr_device *pvr_dev;

	/** @obj: GEM object representing the free list. */
	struct pvr_gem_object *obj;

	/** @fw_obj: FW object representing the FW-side structure. */
	struct pvr_fw_object *fw_obj;

	/** @fw_data: Pointer to CPU mapping of the FW-side structure. */
	struct rogue_fwif_freelist *fw_data;

	/**
	 * @lock: Mutex protecting modification of the free list. Must be held when accessing any
	 *        of the members below.
	 */
	struct mutex lock;

	/** @fw_id: Firmware ID for this object. */
	u32 fw_id;

	/** @current_pages: Current number of pages in free list. */
	u32 current_pages;

	/** @max_pages: Maximum number of pages in free list. */
	u32 max_pages;

	/** @grow_pages: Pages to grow free list by per request. */
	u32 grow_pages;

	/**
	 * @grow_threshold: Percentage of FL memory used that should trigger a
	 *                  new grow request.
	 */
	u32 grow_threshold;

	/**
	 * @ready_pages: Number of pages reserved for FW to use while a grow
	 *               request is being processed.
	 */
	u32 ready_pages;

	/** @mem_block_list: List of memory blocks in this free list. */
	struct list_head mem_block_list;

	/** @hwrt_list: List of HWRTs using this free list. */
	struct list_head hwrt_list;

	/** @initial_num_pages: Initial number of pages in free list. */
	u32 initial_num_pages;

	/** @free_list_gpu_addr: Address of free list in GPU address space. */
	u64 free_list_gpu_addr;
};

struct pvr_free_list *
pvr_free_list_create(struct pvr_file *pvr_file,
		     struct drm_pvr_ioctl_create_free_list_args *args);

void
pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file);

u32
pvr_get_free_list_min_pages(struct pvr_device *pvr_dev);

static __always_inline struct pvr_free_list *
pvr_free_list_get(struct pvr_free_list *free_list)
{
	if (free_list)
		kref_get(&free_list->ref_count);

	return free_list;
}

/**
 * pvr_free_list_lookup() - Lookup free list pointer from handle and file
 * @pvr_file: Pointer to pvr_file structure.
 * @handle: Object handle.
 *
 * Takes reference on free list object. Call pvr_free_list_put() to release.
 *
 * Returns:
 *  * The requested object on success, or
 *  * %NULL on failure (object does not exist in list, is not a free list, or
 *    does not belong to @pvr_file)
 */
static __always_inline struct pvr_free_list *
pvr_free_list_lookup(struct pvr_file *pvr_file, u32 handle)
{
	struct pvr_free_list *free_list;

	xa_lock(&pvr_file->free_list_handles);
	free_list = pvr_free_list_get(xa_load(&pvr_file->free_list_handles, handle));
	xa_unlock(&pvr_file->free_list_handles);

	return free_list;
}

/**
 * pvr_free_list_lookup_id() - Lookup free list pointer from FW ID
 * @pvr_dev: Device pointer.
 * @id: FW object ID.
 *
 * Takes reference on free list object. Call pvr_free_list_put() to release.
 *
 * Returns:
 *  * The requested object on success, or
 *  * %NULL on failure (object does not exist in list, or is not a free list)
 */
static __always_inline struct pvr_free_list *
pvr_free_list_lookup_id(struct pvr_device *pvr_dev, u32 id)
{
	struct pvr_free_list *free_list;

	xa_lock(&pvr_dev->free_list_ids);

	/* Contexts are removed from the ctx_ids set in the context release path,
	 * meaning the ref_count reached zero before they get removed. We need
	 * to make sure we're not trying to acquire a context that's being
	 * destroyed.
	 */
	free_list = xa_load(&pvr_dev->free_list_ids, id);
	if (free_list && !kref_get_unless_zero(&free_list->ref_count))
		free_list = NULL;
	xa_unlock(&pvr_dev->free_list_ids);

	return free_list;
}

void
pvr_free_list_put(struct pvr_free_list *free_list);

void
pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);
void
pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);

void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev,
				    struct rogue_fwif_fwccb_cmd_freelist_gs_data *req);

void
pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev,
				struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req);

#endif /* PVR_FREE_LIST_H */