Loading...
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 */ |