xref: /OK3568_Linux_fs/external/rkwifibt/drivers/rtl8852be/phl/custom/phl_custom.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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