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. */
18struct pvr_fw_object;
19
20/* Forward declaration from pvr_gem.h. */
21struct pvr_gem_object;
22
23/* Forward declaration from pvr_hwrt.h. */
24struct pvr_hwrt_data;
25
26/**
27 * struct pvr_free_list_node - structure representing an allocation in the free
28 *                             list
29 */
30struct 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 */
47struct 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
106struct pvr_free_list *
107pvr_free_list_create(struct pvr_file *pvr_file,
108		     struct drm_pvr_ioctl_create_free_list_args *args);
109
110void
111pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file);
112
113u32
114pvr_get_free_list_min_pages(struct pvr_device *pvr_dev);
115
116static __always_inline struct pvr_free_list *
117pvr_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 */
137static __always_inline struct pvr_free_list *
138pvr_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 */
160static __always_inline struct pvr_free_list *
161pvr_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
180void
181pvr_free_list_put(struct pvr_free_list *free_list);
182
183void
184pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);
185void
186pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data);
187
188void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev,
189				    struct rogue_fwif_fwccb_cmd_freelist_gs_data *req);
190
191void
192pvr_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