1 /******************************************************************************
2 *
3 * Copyright(c) 2019 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15 #define _PHL_CUSTOM_C_
16 #include "../phl_headers.h"
17 #include "phl_custom_fb.h"
18
19 #ifdef CONFIG_PHL_CUSTOM_FEATURE
20
21 #define MAX_DATA_SIZE (512)
22 enum custom_status {
23 CUS_STAT_CMD_USED = BIT0,
24 CUS_STAT_RPT_USED = BIT1,
25 CUS_STAT_RPT_SENDING = BIT2,
26 };
27
28 struct phl_custom_ctx {
29 struct phl_info_t *phl_info;
30 u8 status; /* refer to enum custom_status*/
31 u8 cmd_buf[MAX_DATA_SIZE];
32 u8 rpt_buf[MAX_DATA_SIZE];
33 #ifdef CONFIG_PHL_CUSTOM_FEATURE_FB
34 struct _custom_facebook_ctx fb_ctx;
35 #endif
36 };
37
38 bool
_custom_rpt_notify_check(void * priv,struct phl_msg * msg)39 _custom_rpt_notify_check(void* priv, struct phl_msg* msg)
40 {
41 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
42 bool ret = true;
43 if (!TEST_STATUS_FLAG(ctx->status, CUS_STAT_RPT_USED) ||
44 TEST_STATUS_FLAG(ctx->status, CUS_STAT_RPT_SENDING)) {
45 ret = false;
46 }
47 return ret;
48 }
49
50 void
_custom_rpt_notify_complete(void * priv,struct phl_msg * msg)51 _custom_rpt_notify_complete(void* priv, struct phl_msg* msg)
52 {
53 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
54
55 CLEAR_STATUS_FLAG(ctx->status, CUS_STAT_RPT_USED);
56 CLEAR_STATUS_FLAG(ctx->status, CUS_STAT_RPT_SENDING);
57 }
58
59 void
_custom_rpt_notify_start(void * priv,struct phl_msg * msg,struct phl_msg_attribute * attr)60 _custom_rpt_notify_start(void* priv,
61 struct phl_msg* msg,
62 struct phl_msg_attribute* attr)
63 {
64 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
65 struct rtw_custom_decrpt *evt_rpt = (struct rtw_custom_decrpt *)ctx->rpt_buf;
66
67 SET_STATUS_FLAG(ctx->status, CUS_STAT_RPT_SENDING);
68
69 SET_MSG_MDL_ID_FIELD(msg->msg_id, PHL_MDL_CUSTOM);
70 SET_MSG_EVT_ID_FIELD(msg->msg_id, MSG_EVT_CUSTOM_CMD_DONE);
71
72 msg->inbuf = (u8*) evt_rpt;
73 msg->inlen = evt_rpt->len + sizeof(struct rtw_custom_decrpt);
74
75 attr->completion.completion = _custom_rpt_notify_complete;
76 attr->completion.priv = ctx;
77 }
78
79 static void
_indicate_custome_evt_rpt(struct phl_custom_ctx * ctx)80 _indicate_custome_evt_rpt(struct phl_custom_ctx *ctx)
81 {
82 struct phl_msg msg = {0};
83 struct phl_msg_attribute attr = {0};
84
85 if (!_custom_rpt_notify_check((void*)ctx, &msg))
86 return;
87
88 _custom_rpt_notify_start((void*)ctx, &msg, &attr);
89
90 if (phl_msg_hub_send(ctx->phl_info,
91 &attr, &msg) != RTW_PHL_STATUS_SUCCESS) {
92 PHL_ERR("%s send msg fail\n", __func__);
93 _custom_rpt_notify_complete((void*)ctx, &msg);
94 }
95 }
96 enum rtw_phl_status
_phl_custom_prepare_default_fail_rpt(struct phl_custom_ctx * ctx,struct phl_msg * msg)97 _phl_custom_prepare_default_fail_rpt(struct phl_custom_ctx *ctx,
98 struct phl_msg* msg)
99 {
100 struct rtw_custom_decrpt *cmd = (struct rtw_custom_decrpt *)(msg->inbuf);
101 u8 ret = MDL_RET_FAIL;
102
103 if (TEST_STATUS_FLAG(ctx->status, CUS_STAT_RPT_USED))
104 return RTW_PHL_STATUS_RESOURCE;
105
106 phl_custom_prepare_evt_rpt(ctx,
107 cmd->evt_id,
108 cmd->customer_id,
109 &ret,
110 1);
111 return RTW_PHL_STATUS_SUCCESS;
112 }
113 static enum phl_mdl_ret_code
_phl_custom_hdl_fail_evt(void * dispr,struct phl_custom_ctx * ctx,struct phl_msg * msg)114 _phl_custom_hdl_fail_evt(void* dispr,
115 struct phl_custom_ctx* ctx,
116 struct phl_msg* msg)
117 {
118 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
119 struct rtw_custom_decrpt *cmd = NULL;
120
121 cmd = (struct rtw_custom_decrpt *)(msg->inbuf);
122 switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
123 case MSG_EVT_EDCA_ADJUST:
124 #ifdef CONFIG_PHL_CUSTOM_FEATURE_FB
125 if(cmd->customer_id == CUS_ID_FB) {
126 ret = phl_custom_hdl_fb_fail_evt(dispr,
127 ctx,
128 &(ctx->fb_ctx),
129 msg);
130 }
131 #else
132 ret = MDL_RET_IGNORE;
133 #endif
134 break;
135 default:
136 ret = MDL_RET_IGNORE;
137 break;
138 }
139 return ret;
140 }
141 static enum phl_mdl_ret_code
_phl_custom_hdl_internal_evt(void * dispr,struct phl_custom_ctx * ctx,struct phl_msg * msg)142 _phl_custom_hdl_internal_evt(void* dispr,
143 struct phl_custom_ctx* ctx,
144 struct phl_msg* msg)
145 {
146 enum phl_mdl_ret_code ret = MDL_RET_FAIL;
147 struct rtw_custom_decrpt *cmd = NULL;
148
149 cmd = (struct rtw_custom_decrpt *)(msg->inbuf);
150 switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
151 case MSG_EVT_CUSTOME_FEATURE_ENABLE:
152 case MSG_EVT_CUSTOME_FEATURE_QUERY:
153 case MSG_EVT_CUSTOME_TESTMODE_PARAM:
154 case MSG_EVT_CUSTOME_SET_WIFI_ROLE:
155 case MSG_EVT_AMPDU_CFG:
156 case MSG_EVT_AMPDU_QUERY:
157 case MSG_EVT_PDTHR_CFG:
158 case MSG_EVT_PDTHR_QUERY:
159 case MSG_EVT_POP_CFG:
160 case MSG_EVT_POP_QUERY:
161 #ifdef CONFIG_PHL_CUSTOM_FEATURE_FB
162 if(cmd->customer_id == CUS_ID_FB) {
163 ret = phl_custom_hdl_fb_evt(dispr,
164 ctx,
165 &(ctx->fb_ctx),
166 msg);
167 }
168 #else
169 ret = MDL_RET_IGNORE;
170 #endif
171 break;
172 default:
173 ret = MDL_RET_IGNORE;
174 break;
175 }
176 return ret;
177 }
178 static enum phl_mdl_ret_code
_phl_custom_hdl_external_evt(void * dispr,struct phl_custom_ctx * ctx,struct phl_msg * msg)179 _phl_custom_hdl_external_evt(void* dispr,
180 struct phl_custom_ctx* ctx,
181 struct phl_msg* msg)
182 {
183 return MDL_RET_IGNORE;
184 }
185
186 void
_phl_custom_cmd_completion(void * priv,struct phl_msg * msg)187 _phl_custom_cmd_completion(void* priv, struct phl_msg* msg)
188 {
189 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
190 CLEAR_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED);
191 }
192
193 enum phl_mdl_ret_code
_phl_custom_mdl_init(void * phl_info,void * dispr,void ** priv)194 _phl_custom_mdl_init(void* phl_info,
195 void* dispr,
196 void** priv)
197 {
198 struct phl_info_t *phl = (struct phl_info_t *)phl_info;
199 struct phl_custom_ctx* ctx = NULL;
200 void *d = phl_to_drvpriv(phl);
201
202 FUNCIN();
203 if (priv == NULL)
204 return MDL_RET_FAIL;
205
206 (*priv) = NULL;
207 ctx = (struct phl_custom_ctx *)_os_mem_alloc(d, sizeof(struct phl_custom_ctx));
208 if (ctx == NULL) {
209 PHL_ERR(" %s, alloc fail\n",__FUNCTION__);
210 return MDL_RET_FAIL;
211 }
212 ctx->phl_info = phl_info;
213 (*priv) = (void*)ctx;
214 PHL_INFO(" %s, size phl_custom_ctx(%d)\n",
215 __FUNCTION__, (int)sizeof(struct phl_custom_ctx));
216 return MDL_RET_SUCCESS;
217 }
218 void
_phl_custom_mdl_deinit(void * dispr,void * priv)219 _phl_custom_mdl_deinit(void* dispr, void* priv)
220 {
221 struct phl_custom_ctx *ctx = (struct phl_custom_ctx*)priv;
222 void *d = phl_to_drvpriv(ctx->phl_info);
223
224 _os_mem_free(d, ctx, sizeof(struct phl_custom_ctx));
225 PHL_INFO(" %s\n", __FUNCTION__);
226 }
227 enum phl_mdl_ret_code
_phl_custom_mdl_start(void * dispr,void * priv)228 _phl_custom_mdl_start(void* dispr, void* priv)
229 {
230 enum phl_mdl_ret_code ret = MDL_RET_FAIL;
231
232 FUNCIN();
233 FUNCOUT();
234
235 ret = MDL_RET_SUCCESS;
236 return ret;
237 }
238 enum phl_mdl_ret_code
_phl_custom_mdl_stop(void * dispr,void * priv)239 _phl_custom_mdl_stop(void* dispr, void* priv)
240 {
241 enum phl_mdl_ret_code ret = MDL_RET_FAIL;
242
243 FUNCIN();
244 FUNCOUT();
245
246 ret = MDL_RET_SUCCESS;
247 return ret;
248 }
249 enum phl_mdl_ret_code
_phl_custom_mdl_msg_hdlr(void * dispr,void * priv,struct phl_msg * msg)250 _phl_custom_mdl_msg_hdlr(void* dispr,
251 void* priv,
252 struct phl_msg* msg)
253 {
254 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
255 struct phl_custom_ctx *ctx = (struct phl_custom_ctx*)priv;
256
257 FUNCIN();
258 if (IS_MSG_FAIL(msg->msg_id)) {
259 ret = _phl_custom_hdl_fail_evt(dispr, priv, msg);
260 _indicate_custome_evt_rpt(ctx);
261 return MDL_RET_IGNORE;
262 }
263
264 switch (MSG_MDL_ID_FIELD(msg->msg_id)) {
265 case PHL_MDL_CUSTOM:
266 ret = _phl_custom_hdl_internal_evt(dispr, priv, msg);
267 break;
268 default:
269 ret = _phl_custom_hdl_external_evt(dispr, priv, msg);
270 break;
271 }
272 _indicate_custome_evt_rpt(ctx);
273 FUNCOUT();
274 return ret;
275 }
276 enum phl_mdl_ret_code
_phl_custom_mdl_set_info(void * dispr,void * priv,struct phl_module_op_info * info)277 _phl_custom_mdl_set_info(void* dispr,
278 void* priv,
279 struct phl_module_op_info* info)
280 {
281 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
282 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
283 void *d = phl_to_drvpriv(ctx->phl_info);
284 struct phl_msg msg = {0};
285 struct phl_msg_attribute attr = {0};
286 struct rtw_custom_decrpt *cmd = NULL;
287 u8 idx = 0xff;
288
289 phl_dispr_get_idx(dispr, &idx);
290 FUNCIN();
291 switch (info->op_code) {
292 case BK_MODL_OP_INPUT_CMD:
293 if (TEST_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED) ||
294 info->inlen > MAX_DATA_SIZE) {
295 PHL_ERR("%s buf len err or used\n", __func__);
296 break;
297 }
298 SET_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED);
299 _os_mem_cpy(d, ctx->cmd_buf, info->inbuf, info->inlen);
300 cmd = (struct rtw_custom_decrpt *)ctx->cmd_buf;
301 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_CUSTOM);
302 SET_MSG_EVT_ID_FIELD(msg.msg_id, (u16)cmd->evt_id);
303 msg.inbuf = ctx->cmd_buf;
304 msg.inlen = info->inlen;
305 attr.completion.priv = priv;
306 attr.completion.completion = _phl_custom_cmd_completion;
307 msg.band_idx = idx;
308 if (phl_disp_eng_send_msg(ctx->phl_info,
309 &msg,
310 &attr,
311 NULL) == RTW_PHL_STATUS_SUCCESS) {
312 ret = MDL_RET_SUCCESS;
313 } else {
314 CLEAR_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED);
315 PHL_ERR("%s send msg fail\n", __func__);
316 ret = MDL_RET_FAIL;
317 }
318 break;
319 case BK_MODL_OP_CUS_SET_ROLE_CAP:
320 ret = phl_custom_fb_set_role_cap(dispr,
321 (void *)ctx,
322 &ctx->fb_ctx,
323 info);
324 break;
325 default:
326 break;
327 }
328 FUNCOUT();
329 return ret;
330 }
331 enum phl_mdl_ret_code
_phl_custom_mdl_query_info(void * dispr,void * priv,struct phl_module_op_info * info)332 _phl_custom_mdl_query_info(void* dispr,
333 void* priv,
334 struct phl_module_op_info* info)
335 {
336 enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
337 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)priv;
338 void *d = phl_to_drvpriv(ctx->phl_info);
339 struct phl_msg msg = {0};
340 struct phl_msg_attribute attr = {0};
341 struct rtw_custom_decrpt *cmd = NULL;
342 u8 idx = 0xff;
343
344 FUNCIN();
345 switch(info->op_code) {
346 case BK_MODL_OP_INPUT_CMD:
347 if (TEST_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED) ||
348 info->inlen > MAX_DATA_SIZE) {
349 PHL_ERR("%s buf len err or used\n", __func__);
350 break;
351 }
352 SET_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED);
353 _os_mem_cpy(d, ctx->cmd_buf, info->inbuf, info->inlen);
354 _os_mem_cpy(d, ctx->rpt_buf, info->outbuf, info->outlen);
355 cmd = (struct rtw_custom_decrpt *)ctx->cmd_buf;
356 SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_CUSTOM);
357 SET_MSG_EVT_ID_FIELD(msg.msg_id, (u16)cmd->evt_id);
358 msg.inbuf = ctx->cmd_buf;
359 msg.inlen = info->inlen;
360 msg.outbuf = ctx->rpt_buf;
361 msg.outlen = info->outlen;
362 attr.completion.priv = priv;
363 attr.completion.completion = _phl_custom_cmd_completion;
364 msg.band_idx = idx;
365 if (phl_disp_eng_send_msg(ctx->phl_info,
366 &msg,
367 &attr,
368 NULL) == RTW_PHL_STATUS_SUCCESS) {
369 ret = MDL_RET_SUCCESS;
370 } else {
371 CLEAR_STATUS_FLAG(ctx->status, CUS_STAT_CMD_USED);
372 PHL_ERR("%s send msg fail\n", __func__);
373 ret = MDL_RET_FAIL;
374 }
375 break;
376 case BK_MODL_OP_CUS_UPDATE_ROLE_CAP:
377 ret = phl_custom_fb_update_opt_ie(dispr, (void*)ctx, &ctx->fb_ctx, info);
378 break;
379 default:
380 break;
381 }
382
383 FUNCOUT();
384 return ret;
385 }
386
387 enum rtw_phl_status
phl_register_custom_module(struct phl_info_t * phl_info,u8 band_idx)388 phl_register_custom_module(struct phl_info_t *phl_info, u8 band_idx)
389 {
390 enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
391 struct phl_bk_module_ops bk_ops = {0};
392
393 bk_ops.init = _phl_custom_mdl_init;
394 bk_ops.deinit = _phl_custom_mdl_deinit;
395 bk_ops.start = _phl_custom_mdl_start;
396 bk_ops.stop = _phl_custom_mdl_stop;
397 bk_ops.msg_hdlr = _phl_custom_mdl_msg_hdlr;
398 bk_ops.query_info = _phl_custom_mdl_query_info;
399 bk_ops.set_info = _phl_custom_mdl_set_info;
400
401 phl_status = phl_disp_eng_register_module(phl_info,
402 band_idx,
403 PHL_MDL_CUSTOM,
404 &bk_ops);
405 if (RTW_PHL_STATUS_SUCCESS != phl_status)
406 PHL_ERR("%s register Custom module in cmd disp failed\n", __func__);
407
408 return phl_status;
409
410 }
411
412 enum rtw_phl_status
phl_custom_prepare_evt_rpt(void * custom_ctx,u32 evt_id,u32 customer_id,u8 * rpt,u32 rpt_len)413 phl_custom_prepare_evt_rpt(void *custom_ctx,
414 u32 evt_id,
415 u32 customer_id,
416 u8 *rpt,
417 u32 rpt_len)
418 {
419 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)custom_ctx;
420 struct rtw_custom_decrpt *evt_rpt = (struct rtw_custom_decrpt *)ctx->rpt_buf;
421 void *d = phl_to_drvpriv(ctx->phl_info);
422 u8* val = (u8*)(evt_rpt +1);
423
424 if ((rpt_len > (MAX_DATA_SIZE - sizeof(struct rtw_custom_decrpt))) ||
425 TEST_STATUS_FLAG(ctx->status, CUS_STAT_RPT_USED))
426 return RTW_PHL_STATUS_RESOURCE;
427
428 SET_STATUS_FLAG(ctx->status, CUS_STAT_RPT_USED);
429 evt_rpt->evt_id = evt_id;
430 evt_rpt->customer_id = customer_id;
431 evt_rpt->len = rpt_len;
432 _os_mem_cpy(d, val, rpt, rpt_len);
433 return RTW_PHL_STATUS_SUCCESS;
434 }
435 struct phl_info_t*
phl_custom_get_phl_info(void * custom_ctx)436 phl_custom_get_phl_info(void *custom_ctx)
437 {
438 struct phl_custom_ctx *ctx = (struct phl_custom_ctx *)custom_ctx;
439
440 return ctx->phl_info;
441 }
442
443 /**
444 * phl_custom_init_role_cap
445 * 1. role cap customization
446 * input:
447 * @phl_info: (struct phl_info_t *)
448 * @hw_band:hw_band
449 * @role_cap: (struct role_cap_t)
450 * return: rtw_phl_status
451 */
452 enum rtw_phl_status
phl_custom_init_role_cap(struct phl_info_t * phl_info,u8 hw_band,struct role_cap_t * role_cap)453 phl_custom_init_role_cap(struct phl_info_t *phl_info,
454 u8 hw_band,
455 struct role_cap_t *role_cap)
456 {
457 enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
458
459 status = phl_custom_fb_init_role_cap(phl_info, hw_band, role_cap);
460
461 return status;
462 }
463 #endif
464