1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
4 */
5
6 #include <drm/drm_device.h>
7 #include <drm/drm_managed.h>
8 #include <drm/drm_print.h>
9 #include <linux/bitops.h>
10 #include <linux/bitmap.h>
11 #include <linux/slab.h>
12
13 #include "aie2_solver.h"
14
15 struct partition_node {
16 struct list_head list;
17 u32 nshared; /* # shared requests */
18 u32 start_col; /* start column */
19 u32 ncols; /* # columns */
20 bool exclusive; /* can not be shared if set */
21 };
22
23 struct solver_node {
24 struct list_head list;
25 u64 rid; /* Request ID from consumer */
26
27 struct partition_node *pt_node;
28 void *cb_arg;
29 u32 dpm_level;
30 u32 cols_len;
31 u32 start_cols[] __counted_by(cols_len);
32 };
33
34 struct solver_rgroup {
35 u32 rgid;
36 u32 nnode;
37 u32 npartition_node;
38
39 DECLARE_BITMAP(resbit, XRS_MAX_COL);
40 struct list_head node_list;
41 struct list_head pt_node_list;
42 };
43
44 struct solver_state {
45 struct solver_rgroup rgp;
46 struct init_config cfg;
47 struct xrs_action_ops *actions;
48 };
49
calculate_gops(struct aie_qos * rqos)50 static u32 calculate_gops(struct aie_qos *rqos)
51 {
52 u32 service_rate = 0;
53
54 if (rqos->latency)
55 service_rate = (1000 / rqos->latency);
56
57 if (rqos->fps > service_rate)
58 return rqos->fps * rqos->gops;
59
60 return service_rate * rqos->gops;
61 }
62
63 /*
64 * qos_meet() - Check the QOS request can be met.
65 */
qos_meet(struct solver_state * xrs,struct aie_qos * rqos,u32 cgops)66 static int qos_meet(struct solver_state *xrs, struct aie_qos *rqos, u32 cgops)
67 {
68 u32 request_gops = calculate_gops(rqos) * xrs->cfg.sys_eff_factor;
69
70 if (request_gops <= cgops)
71 return 0;
72
73 return -EINVAL;
74 }
75
76 /*
77 * sanity_check() - Do a basic sanity check on allocation request.
78 */
sanity_check(struct solver_state * xrs,struct alloc_requests * req)79 static int sanity_check(struct solver_state *xrs, struct alloc_requests *req)
80 {
81 struct cdo_parts *cdop = &req->cdo;
82 struct aie_qos *rqos = &req->rqos;
83 u32 cu_clk_freq;
84
85 if (cdop->ncols > xrs->cfg.total_col)
86 return -EINVAL;
87
88 /*
89 * We can find at least one CDOs groups that meet the
90 * GOPs requirement.
91 */
92 cu_clk_freq = xrs->cfg.clk_list.cu_clk_list[xrs->cfg.clk_list.num_levels - 1];
93
94 if (qos_meet(xrs, rqos, cdop->qos_cap.opc * cu_clk_freq / 1000))
95 return -EINVAL;
96
97 return 0;
98 }
99
is_valid_qos_dpm_params(struct aie_qos * rqos)100 static bool is_valid_qos_dpm_params(struct aie_qos *rqos)
101 {
102 /*
103 * gops is retrieved from the xmodel, so it's always set
104 * fps and latency are the configurable params from the application
105 */
106 if (rqos->gops > 0 && (rqos->fps > 0 || rqos->latency > 0))
107 return true;
108
109 return false;
110 }
111
set_dpm_level(struct solver_state * xrs,struct alloc_requests * req,u32 * dpm_level)112 static int set_dpm_level(struct solver_state *xrs, struct alloc_requests *req, u32 *dpm_level)
113 {
114 struct solver_rgroup *rgp = &xrs->rgp;
115 struct cdo_parts *cdop = &req->cdo;
116 struct aie_qos *rqos = &req->rqos;
117 u32 freq, max_dpm_level, level;
118 struct solver_node *node;
119
120 max_dpm_level = xrs->cfg.clk_list.num_levels - 1;
121 /* If no QoS parameters are passed, set it to the max DPM level */
122 if (!is_valid_qos_dpm_params(rqos)) {
123 level = max_dpm_level;
124 goto set_dpm;
125 }
126
127 /* Find one CDO group that meet the GOPs requirement. */
128 for (level = 0; level < max_dpm_level; level++) {
129 freq = xrs->cfg.clk_list.cu_clk_list[level];
130 if (!qos_meet(xrs, rqos, cdop->qos_cap.opc * freq / 1000))
131 break;
132 }
133
134 /* set the dpm level which fits all the sessions */
135 list_for_each_entry(node, &rgp->node_list, list) {
136 if (node->dpm_level > level)
137 level = node->dpm_level;
138 }
139
140 set_dpm:
141 *dpm_level = level;
142 return xrs->cfg.actions->set_dft_dpm_level(xrs->cfg.ddev, level);
143 }
144
rg_search_node(struct solver_rgroup * rgp,u64 rid)145 static struct solver_node *rg_search_node(struct solver_rgroup *rgp, u64 rid)
146 {
147 struct solver_node *node;
148
149 list_for_each_entry(node, &rgp->node_list, list) {
150 if (node->rid == rid)
151 return node;
152 }
153
154 return NULL;
155 }
156
remove_partition_node(struct solver_rgroup * rgp,struct partition_node * pt_node)157 static void remove_partition_node(struct solver_rgroup *rgp,
158 struct partition_node *pt_node)
159 {
160 pt_node->nshared--;
161 if (pt_node->nshared > 0)
162 return;
163
164 list_del(&pt_node->list);
165 rgp->npartition_node--;
166
167 bitmap_clear(rgp->resbit, pt_node->start_col, pt_node->ncols);
168 kfree(pt_node);
169 }
170
remove_solver_node(struct solver_rgroup * rgp,struct solver_node * node)171 static void remove_solver_node(struct solver_rgroup *rgp,
172 struct solver_node *node)
173 {
174 list_del(&node->list);
175 rgp->nnode--;
176
177 if (node->pt_node)
178 remove_partition_node(rgp, node->pt_node);
179
180 kfree(node);
181 }
182
get_free_partition(struct solver_state * xrs,struct solver_node * snode,struct alloc_requests * req)183 static int get_free_partition(struct solver_state *xrs,
184 struct solver_node *snode,
185 struct alloc_requests *req)
186 {
187 struct partition_node *pt_node;
188 u32 ncols = req->cdo.ncols;
189 u32 col, i;
190
191 for (i = 0; i < snode->cols_len; i++) {
192 col = snode->start_cols[i];
193 if (find_next_bit(xrs->rgp.resbit, XRS_MAX_COL, col) >= col + ncols)
194 break;
195 }
196
197 if (i == snode->cols_len)
198 return -ENODEV;
199
200 pt_node = kzalloc(sizeof(*pt_node), GFP_KERNEL);
201 if (!pt_node)
202 return -ENOMEM;
203
204 pt_node->nshared = 1;
205 pt_node->start_col = col;
206 pt_node->ncols = ncols;
207
208 /*
209 * Always set exclusive to false for now.
210 */
211 pt_node->exclusive = false;
212
213 list_add_tail(&pt_node->list, &xrs->rgp.pt_node_list);
214 xrs->rgp.npartition_node++;
215 bitmap_set(xrs->rgp.resbit, pt_node->start_col, pt_node->ncols);
216
217 snode->pt_node = pt_node;
218
219 return 0;
220 }
221
allocate_partition(struct solver_state * xrs,struct solver_node * snode,struct alloc_requests * req)222 static int allocate_partition(struct solver_state *xrs,
223 struct solver_node *snode,
224 struct alloc_requests *req)
225 {
226 struct partition_node *pt_node, *rpt_node = NULL;
227 int idx, ret;
228
229 ret = get_free_partition(xrs, snode, req);
230 if (!ret)
231 return ret;
232
233 /* try to get a share-able partition */
234 list_for_each_entry(pt_node, &xrs->rgp.pt_node_list, list) {
235 if (pt_node->exclusive)
236 continue;
237
238 if (rpt_node && pt_node->nshared >= rpt_node->nshared)
239 continue;
240
241 for (idx = 0; idx < snode->cols_len; idx++) {
242 if (snode->start_cols[idx] != pt_node->start_col)
243 continue;
244
245 if (req->cdo.ncols != pt_node->ncols)
246 continue;
247
248 rpt_node = pt_node;
249 break;
250 }
251 }
252
253 if (!rpt_node)
254 return -ENODEV;
255
256 rpt_node->nshared++;
257 snode->pt_node = rpt_node;
258
259 return 0;
260 }
261
create_solver_node(struct solver_state * xrs,struct alloc_requests * req)262 static struct solver_node *create_solver_node(struct solver_state *xrs,
263 struct alloc_requests *req)
264 {
265 struct cdo_parts *cdop = &req->cdo;
266 struct solver_node *node;
267 int ret;
268
269 node = kzalloc(struct_size(node, start_cols, cdop->cols_len), GFP_KERNEL);
270 if (!node)
271 return ERR_PTR(-ENOMEM);
272
273 node->rid = req->rid;
274 node->cols_len = cdop->cols_len;
275 memcpy(node->start_cols, cdop->start_cols, cdop->cols_len * sizeof(u32));
276
277 ret = allocate_partition(xrs, node, req);
278 if (ret)
279 goto free_node;
280
281 list_add_tail(&node->list, &xrs->rgp.node_list);
282 xrs->rgp.nnode++;
283 return node;
284
285 free_node:
286 kfree(node);
287 return ERR_PTR(ret);
288 }
289
fill_load_action(struct solver_state * xrs,struct solver_node * snode,struct xrs_action_load * action)290 static void fill_load_action(struct solver_state *xrs,
291 struct solver_node *snode,
292 struct xrs_action_load *action)
293 {
294 action->rid = snode->rid;
295 action->part.start_col = snode->pt_node->start_col;
296 action->part.ncols = snode->pt_node->ncols;
297 }
298
xrs_allocate_resource(void * hdl,struct alloc_requests * req,void * cb_arg)299 int xrs_allocate_resource(void *hdl, struct alloc_requests *req, void *cb_arg)
300 {
301 struct xrs_action_load load_act;
302 struct solver_node *snode;
303 struct solver_state *xrs;
304 u32 dpm_level;
305 int ret;
306
307 xrs = (struct solver_state *)hdl;
308
309 ret = sanity_check(xrs, req);
310 if (ret) {
311 drm_err(xrs->cfg.ddev, "invalid request");
312 return ret;
313 }
314
315 if (rg_search_node(&xrs->rgp, req->rid)) {
316 drm_err(xrs->cfg.ddev, "rid %lld is in-use", req->rid);
317 return -EEXIST;
318 }
319
320 snode = create_solver_node(xrs, req);
321 if (IS_ERR(snode))
322 return PTR_ERR(snode);
323
324 fill_load_action(xrs, snode, &load_act);
325 ret = xrs->cfg.actions->load(cb_arg, &load_act);
326 if (ret)
327 goto free_node;
328
329 ret = set_dpm_level(xrs, req, &dpm_level);
330 if (ret)
331 goto free_node;
332
333 snode->dpm_level = dpm_level;
334 snode->cb_arg = cb_arg;
335
336 drm_dbg(xrs->cfg.ddev, "start col %d ncols %d\n",
337 snode->pt_node->start_col, snode->pt_node->ncols);
338
339 return 0;
340
341 free_node:
342 remove_solver_node(&xrs->rgp, snode);
343
344 return ret;
345 }
346
xrs_release_resource(void * hdl,u64 rid)347 int xrs_release_resource(void *hdl, u64 rid)
348 {
349 struct solver_state *xrs = hdl;
350 struct solver_node *node;
351
352 node = rg_search_node(&xrs->rgp, rid);
353 if (!node) {
354 drm_err(xrs->cfg.ddev, "node not exist");
355 return -ENODEV;
356 }
357
358 xrs->cfg.actions->unload(node->cb_arg);
359 remove_solver_node(&xrs->rgp, node);
360
361 return 0;
362 }
363
xrsm_init(struct init_config * cfg)364 void *xrsm_init(struct init_config *cfg)
365 {
366 struct solver_rgroup *rgp;
367 struct solver_state *xrs;
368
369 xrs = drmm_kzalloc(cfg->ddev, sizeof(*xrs), GFP_KERNEL);
370 if (!xrs)
371 return NULL;
372
373 memcpy(&xrs->cfg, cfg, sizeof(*cfg));
374
375 rgp = &xrs->rgp;
376 INIT_LIST_HEAD(&rgp->node_list);
377 INIT_LIST_HEAD(&rgp->pt_node_list);
378
379 return xrs;
380 }
381