xref: /linux/drivers/gpu/drm/imagination/pvr_free_list.h (revision daa2be74b1b2302004945b2a5e32424e177cc7da)
1 /* SPDX-License-Identifier: GPL-2.0-only OR MIT */
2 /* Copyright (c) 2023 Imagination Technologies Ltd. */
3 
4 #ifndef PVR_FREE_LIST_H
5 #define PVR_FREE_LIST_H
6 
7 #include <linux/compiler_attributes.h>
8 #include <linux/kref.h>
9 #include <linux/list.h>
10 #include <linux/mutex.h>
11 #include <linux/types.h>
12 #include <linux/xarray.h>
13 #include <uapi/drm/pvr_drm.h>
14 
15 #include "pvr_device.h"
16 
17 /* Forward declaration from pvr_gem.h. */
18 struct pvr_fw_object;
19 
20 /* Forward declaration from pvr_gem.h. */
21 struct pvr_gem_object;
22 
23 /* Forward declaration from pvr_hwrt.h. */
24 struct pvr_hwrt_data;
25 
26 /**
27  * struct pvr_free_list_node - structure representing an allocation in the free
28  *                             list
29  */
30 struct pvr_free_list_node {
31 	/** @node: List node for &pvr_free_list.mem_block_list. */
32 	struct list_head node;
33 
34 	/** @free_list: Pointer to owning free list. */
35 	struct pvr_free_list *free_list;
36 
37 	/** @num_pages: Number of pages in this node. */
38 	u32 num_pages;
39 
40 	/** @mem_obj: GEM object representing the pages in this node. */
41 	struct pvr_gem_object *mem_obj;
42 };
43 
44 /**
45  * struct pvr_free_list - structure representing a free list
46  */
47 struct pvr_free_list {
48 	/** @ref_count: Reference count of object. */
49 	struct kref ref_count;
50 
51 	/** @pvr_dev: Pointer to device that owns this object. */
52 	struct pvr_device *pvr_dev;
53 
54 	/** @obj: GEM object representing the free list. */
55 	struct pvr_gem_object *obj;
56 
57 	/** @fw_obj: FW object representing the FW-side structure. */
58 	struct pvr_fw_object *fw_obj;
59 
60 	/** @fw_data: Pointer to CPU mapping of the FW-side structure. */
61 	struct rogue_fwif_freelist *fw_data;
62 
63 	/**
64 	 * @lock: Mutex protecting modification of the free list. Must be held when accessing any
65 	 *        of the members below.
66 	 */
67 	struct mutex lock;
68 
69 	/** @fw_id: Firmware ID for this object. */
70 	u32 fw_id;
71 
72 	/** @current_pages: Current number of pages in free list. */
73 	u32 current_pages;
74 
75 	/** @max_pages: Maximum number of pages in free list. */
76 	u32 max_pages;
77 
78 	/** @grow_pages: Pages to grow free list by per request. */
79 	u32 grow_pages;
80 
81 	/**
82 	 * @grow_threshold: Percentage of FL memory used that should trigger a
83 	 *                  new grow request.
84 	 */
85 	u32 grow_threshold;
86 
87 	/**
88 	 * @ready_pages: Number of pages reserved for FW to use while a grow
89 	 *               request is being processed.
90 	 */
91 	u32 ready_pages;
92 
93 	/** @mem_block_list: List of memory blocks in this free list. */
94 	struct list_head mem_block_list;
95 
96 	/** @hwrt_list: List of HWRTs using this free list. */
97 	struct list_head hwrt_list;
98 
99 	/** @initial_num_pages: Initial number of pages in free list. */
100 	u32 initial_num_pages;
101 
102 	/** @free_list_gpu_addr: Address of free list in GPU address space. */
103 	u64 free_list_gpu_addr;
104 };
105 
106 struct pvr_free_list *
107 pvr_free_list_create(struct pvr_file *pvr_file,
108 		     struct drm_pvr_ioctl_create_free_list_args *args);
109 
110 void
111 pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file);
112 
113 u32
114 pvr_get_free_list_min_pages(struct pvr_device *pvr_dev);
115 
116 static __always_inline struct pvr_free_list *
117 pvr_free_list_get(struct pvr_free_list *free_list)
118 {
119 	if (free_list)
120 		kref_get(&free_list->ref_count);
121 
122 	return free_list;
123 }
124 
125 /**
126  * pvr_free_list_lookup() - Lookup free list pointer from handle and file
127  * @pvr_file: Pointer to pvr_file structure.
128  * @handle: Object handle.
129  *
130  * Takes reference on free list object. Call pvr_free_list_put() to release.
131  *
132  * Returns:
133  *  * The requested object on success, or
134  *  * %NULL on failure (object does not exist in list, is not a free list, or
135  *    does not belong to @pvr_file)
136  */
137 static __always_inline struct pvr_free_list *
138 pvr_free_list_lookup(struct pvr_file *pvr_file, u32 handle)
139 {
140 	struct pvr_free_list *free_list;
141 
142 	xa_lock(&pvr_file->free_list_handles);
143 	free_list = pvr_free_list_get(xa_load(&pvr_file->free_list_handles, handle));
144 	xa_unlock(&pvr_file->free_list_handles);
145 
146 	return free_list;
147 }
148 
149 /**
150  * pvr_free_list_lookup_id() - Lookup free list pointer from FW ID
151  * @pvr_dev: Device pointer.
152  * @id: FW object ID.
153  *
154  * Takes reference on free list object. Call pvr_free_list_put() to release.
155  *
156  * Returns:
157  *  * The requested object on success, or
158  *  * %NULL on failure (object does not exist in list, or is not a free list)
159  */
160 static __always_inline struct pvr_free_list *
161 pvr_free_list_lookup_id(struct pvr_device *pvr_dev, u32 id)
162 {
163 	struct pvr_free_list *free_list;
164 
165 	xa_lock(&pvr_dev->free_list_ids);
166 
167 	/* Contexts are removed from the ctx_ids set in the context release path,
168 	 * meaning the ref_count reached zero before they get removed. We need
169 	 * to make sure we're not trying to acquire a context that's being
170 	 * destroyed.
171 	 */
172 	free_list = xa_load(&pvr_dev->free_list_ids, id);
173 	if (free_list && !kref_get_unless_zero(&free_list->ref_count))
174 		free_list = NULL;
175 	xa_unlock(&pvr_dev->free_list_ids);
176 
177 	return free_list;
178 }
179 
180 void
181 pvr_free_list_put(struct pvr_free_list *free_list);
182 
183 void
184 pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);
185 void
186 pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);
187 
188 void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev,
189 				    struct rogue_fwif_fwccb_cmd_freelist_gs_data *req);
190 
191 void
192 pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev,
193 				struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req);
194 
195 #endif /* PVR_FREE_LIST_H */
196