/****************************************************************************** * * Copyright(c) 2019 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #define _PHL_CMD_DISPR_C_ #include "phl_headers.h" #ifdef CONFIG_CMD_DISP #ifdef CONFIG_PHL_MSG_NUM #define MAX_PHL_MSG_NUM CONFIG_PHL_MSG_NUM #else #define MAX_PHL_MSG_NUM (24) #endif #define MAX_CMD_REQ_NUM (8) #define MODL_MASK_LEN (PHL_BK_MDL_END/8) #define GEN_VALID_HDL(_idx) ((u32)(BIT31 | (u32)(_idx))) #define IS_HDL_VALID(_hdl) ((_hdl) & BIT31) #define GET_IDX_FROM_HDL(_hdl) ((u8)((_hdl) & 0xFF)) #define GET_CUR_PENDING_EVT( _obj, _mdl_id) \ ((u16)((_obj)->mdl_info[(_mdl_id)].pending_evt_id)) #define SET_CUR_PENDING_EVT( _obj, _mdl_id, _evt_id) \ ((_obj)->mdl_info[(_mdl_id)].pending_evt_id = (_evt_id)) #define IS_EXCL_MDL(_obj, _mdl) ((_obj)->exclusive_mdl == (_mdl)) #define SET_EXCL_MDL(_obj, _mdl) ((_obj)->exclusive_mdl = (_mdl)) #define CLEAR_EXCL_MDL(_obj) ((_obj)->exclusive_mdl = PHL_MDL_ID_MAX) #define STOP_DISPATCH_MSG(_ret) \ ((_ret) != MDL_RET_SUCCESS && (_ret) != MDL_RET_IGNORE) #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ #define SET_MDL_HANDLE( _obj, _mdl_id, _handle) \ ((_obj)->mdl_info[(_mdl_id)].handle = (void*)(_handle)) #define GET_MDL_HANDLE( _obj, _mdl_id) \ ((_obj)->mdl_info[(_mdl_id)].handle) #endif enum phl_msg_status { MSG_STATUS_ENQ = BIT0, MSG_STATUS_RUN = BIT1, MSG_STATUS_NOTIFY_COMPLETE = BIT2, MSG_STATUS_CANCEL = BIT3, MSG_STATUS_PRE_PHASE = BIT4, MSG_STATUS_FAIL = BIT5, MSG_STATUS_OWNER_BK_MDL = BIT6, MSG_STATUS_OWNER_REQ = BIT7, MSG_STATUS_CLR_SNDR_MSG_IF_PENDING = BIT8, MSG_STATUS_PENDING = BIT9, MSG_STATUS_FOR_ABORT = BIT10, MSG_STATUS_PENDING_DURING_CANNOT_IO = BIT11, }; enum cmd_req_status { REQ_STATUS_ENQ = BIT0, REQ_STATUS_RUN = BIT1, REQ_STATUS_CANCEL = BIT2, REQ_STATUS_LAST_PERMIT = BIT3, REQ_STATUS_PREPARE = BIT4, }; enum phl_mdl_status { MDL_INIT = BIT0, MDL_STARTED = BIT1, }; enum dispatcher_status { DISPR_INIT = BIT0, DISPR_STARTED = BIT1, DISPR_SHALL_STOP = BIT2, DISPR_MSGQ_INIT = BIT3, DISPR_REQ_INIT = BIT4, DISPR_NOTIFY_IDLE = BIT5, DISPR_CLR_PEND_MSG = BIT6, DISPR_CTRL_PRESENT = BIT7, DISPR_WAIT_ABORT_MSG_DONE = BIT8, DISPR_CANNOT_IO = BIT9, }; enum token_op_type { TOKEN_OP_ADD_CMD_REQ = 1, TOKEN_OP_FREE_CMD_REQ = 2, TOKEN_OP_CANCEL_CMD_REQ = 3, TOKEN_OP_RENEW_CMD_REQ = 4, }; /** * phl_bk_module - instance of phl background module, * @status: contain mgnt status flags, refer to enum phl_mdl_status * @id: refer to enum phl_module_id * @priv: private context * @ops: interface to interacting with phl_module */ struct phl_bk_module { _os_list list; u8 status; u8 id; void *priv; struct phl_bk_module_ops ops; }; #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ struct dispr_msg_attr { struct msg_self_def_seq self_def_seq; }; #endif /** * phl_dispr_msg_ex - phl msg extension, * @status: contain mgnt status flags, refer to enum phl_msg_status * @idx: idx in original msg_ex pool * @msg: msg content from external module * @premap: notifty map in pre-role phase, refer to enum phl_module_id * @postmap: notifty map in post-role phase, refer to enum phl_module_id * @completion: msg completion routine. * @priv: private context to completion routine. * @module: module handle of msg source, only used when msg fails */ struct phl_dispr_msg_ex { _os_list list; u16 status; u8 idx; struct phl_msg msg; u8 premap[MODL_MASK_LEN]; u8 postmap[MODL_MASK_LEN]; struct msg_completion_routine completion; struct phl_bk_module *module; /* module handle which assign in msg_id*/ #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ struct dispr_msg_attr *attr; #endif }; /** * phl_token_op_info - for internal mgnt purpose, * @info: mgnt data */ struct phl_token_op_info { _os_list list; u8 used; enum token_op_type type; u8 data; }; /** * phl_cmd_token_req_ex - cmd token request extension, * @status: contain mgnt status flags, refer to enum cmd_req_status * @idx: idx in original req_ex pool * @req: req content from external module. */ struct phl_cmd_token_req_ex { _os_list list; u8 idx; u8 status; struct phl_cmd_token_req req; struct phl_token_op_info add_req_info; struct phl_token_op_info free_req_info; }; struct mdl_mgnt_info { u16 pending_evt_id; #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ void* handle; #endif }; /** * cmd_dispatcher, * @idx: idx in dispatch engine, corresponding to band idx * @status: contain mgnt status flags, refer to enum dispatcher_status * @phl_info: for general reference usage. * @module_q: module queue that link each modules based on priority * @msg_ex_pool: msg extension pool * @bk_thread: background thread * @token_req_ex_pool: req extension pool * @token_cnt: current token count, * cmd req can be executed when dispatcher's token count is 0 * @bitmap: cosist of existing background modules loaded in current dispatcher, * refer to enum phl_module_id * @basemap: BK modules that must be notified when handling msg * @controller: instance of dispr controller module * @renew_req_info: used to trigger next token req registration * @exclusive_mdl: In certain conditions, like dev IO status change, * dispr would only allow designated module to send msg and cancel the rest, */ struct cmd_dispatcher { u8 idx; u16 status; struct phl_info_t *phl_info; struct phl_queue module_q[PHL_MDL_PRI_MAX]; struct phl_dispr_msg_ex msg_ex_pool[MAX_PHL_MSG_NUM]; _os_sema msg_q_sema; /* wake up background thread in SOLO_THREAD_MODE*/ struct phl_queue msg_wait_q; struct phl_queue msg_idle_q; struct phl_queue msg_pend_q; _os_thread bk_thread; struct phl_cmd_token_req_ex token_req_ex_pool[MAX_CMD_REQ_NUM]; struct phl_queue token_req_wait_q; struct phl_queue token_req_idle_q; struct phl_queue token_op_q; _os_lock token_op_q_lock; _os_atomic token_cnt; // atomic struct phl_cmd_token_req_ex *cur_cmd_req; u8 bitmap[MODL_MASK_LEN]; u8 basemap[MODL_MASK_LEN]; struct mdl_mgnt_info mdl_info[PHL_MDL_ID_MAX]; struct phl_bk_module controller; struct phl_token_op_info renew_req_info; u8 exclusive_mdl; }; enum rtw_phl_status dispr_process_token_req(struct cmd_dispatcher *obj); void send_bk_msg_phy_on(struct cmd_dispatcher *obj); void send_bk_msg_phy_idle(struct cmd_dispatcher *obj); enum rtw_phl_status send_dev_io_status_change(struct cmd_dispatcher *obj, u8 allow_io); void _notify_dispr_controller(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex); static u8 dispr_enqueue_token_op_info(struct cmd_dispatcher *obj, struct phl_token_op_info *op_info, enum token_op_type type, u8 data); #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ static void free_dispr_attr(void *d, struct dispr_msg_attr **dispr_attr); static enum phl_mdl_ret_code run_self_def_seq(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, enum phl_bk_module_priority priority, u8 pre_prot_phase); #endif inline static enum phl_bk_module_priority _get_mdl_priority(enum phl_module_id id) { if (id < PHL_BK_MDL_ROLE_START) return PHL_MDL_PRI_MAX; else if (id <= PHL_BK_MDL_ROLE_END) return PHL_MDL_PRI_ROLE; else if ( id <= PHL_BK_MDL_MDRY_END) return PHL_MDL_PRI_MANDATORY; else if (id <= PHL_BK_MDL_OPT_END) return PHL_MDL_PRI_OPTIONAL; else return PHL_MDL_PRI_MAX; } inline static u8 _is_bitmap_empty(void *d, u8 *bitmap) { u8 empty[MODL_MASK_LEN] = {0}; return (!_os_mem_cmp(d, bitmap, empty, MODL_MASK_LEN))?(true):(false); } inline static void _print_bitmap(u8 *bitmap) { u8 k = 0; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "print bitmap: \n"); for (k = 0; k < MODL_MASK_LEN; k++) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_,"[%d]:0x%x\n", k, bitmap[k]); } } static void notify_bk_thread(struct cmd_dispatcher *obj) { void *d = phl_to_drvpriv(obj->phl_info); if (disp_eng_is_solo_thread_mode(obj->phl_info)) _os_sema_up(d, &(obj->msg_q_sema)); else disp_eng_notify_share_thread(obj->phl_info, (void*)obj); } static void on_abort_msg_complete(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { /* since struct phl_token_op_info is used to synchronously handle token req in background thread * here use add_req_info to notify background thread to run dispr_process_token_req again before handling next msg */ CLEAR_STATUS_FLAG(obj->status, DISPR_WAIT_ABORT_MSG_DONE); dispr_enqueue_token_op_info(obj, &obj->renew_req_info, TOKEN_OP_RENEW_CMD_REQ, 0xff); } static u8 pop_front_idle_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex **msg) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_msg = NULL; (*msg) = NULL; if (pq_pop(d, &(obj->msg_idle_q), &new_msg, _first, _bh)) { (*msg) = (struct phl_dispr_msg_ex *)new_msg; (*msg)->status = 0; (*msg)->module = NULL; (*msg)->completion.priv = NULL; (*msg)->completion.completion = NULL; _os_mem_set(d, (*msg)->premap, 0, MODL_MASK_LEN); _os_mem_set(d, (*msg)->postmap, 0, MODL_MASK_LEN); _os_mem_set(d, &((*msg)->msg), 0, sizeof(struct phl_msg)); #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ (*msg)->attr = NULL; #endif PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: remain cnt(%d)\n", __FUNCTION__, obj->msg_idle_q.cnt); return true; } else { return false; } } static void push_back_idle_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { void *d = phl_to_drvpriv(obj->phl_info); if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_NOTIFY_COMPLETE) && ex->completion.completion) { if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL)) SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_CANCEL); ex->completion.completion(ex->completion.priv, &(ex->msg)); CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_NOTIFY_COMPLETE); } if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_FOR_ABORT)) on_abort_msg_complete(obj, ex); ex->status = 0; if(GET_CUR_PENDING_EVT(obj, MSG_MDL_ID_FIELD(ex->msg.msg_id)) == MSG_EVT_ID_FIELD(ex->msg.msg_id)) SET_CUR_PENDING_EVT(obj, MSG_MDL_ID_FIELD(ex->msg.msg_id), MSG_EVT_MAX); ex->msg.msg_id = 0; #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ free_dispr_attr(d, &(ex->attr)); #endif pq_push(d, &(obj->msg_idle_q), &(ex->list), _tail, _bh); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: remain cnt(%d)\n", __FUNCTION__, obj->msg_idle_q.cnt); } static u8 pop_front_wait_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex **msg) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_msg = NULL; (*msg) = NULL; if (pq_pop(d, &(obj->msg_wait_q), &new_msg, _first, _bh)) { (*msg) = (struct phl_dispr_msg_ex *)new_msg; SET_STATUS_FLAG((*msg)->status, MSG_STATUS_RUN); CLEAR_STATUS_FLAG((*msg)->status, MSG_STATUS_ENQ); CLEAR_STATUS_FLAG((*msg)->status, MSG_STATUS_PENDING); return true; } else { return false; } } static void push_back_wait_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { void *d = phl_to_drvpriv(obj->phl_info); SET_STATUS_FLAG(ex->status, MSG_STATUS_ENQ); CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_RUN); pq_push(d, &(obj->msg_wait_q), &(ex->list), _tail, _bh); notify_bk_thread(obj); } u8 is_higher_priority(void *d, void *priv,_os_list *input, _os_list *obj) { struct phl_dispr_msg_ex *ex_input = (struct phl_dispr_msg_ex *)input; struct phl_dispr_msg_ex *ex_obj = (struct phl_dispr_msg_ex *)obj; if (IS_DISPR_CTRL(MSG_MDL_ID_FIELD(ex_input->msg.msg_id)) && !IS_DISPR_CTRL(MSG_MDL_ID_FIELD(ex_obj->msg.msg_id))) return true; return false; } static void insert_msg_by_priority(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { void *d = phl_to_drvpriv(obj->phl_info); SET_STATUS_FLAG(ex->status, MSG_STATUS_ENQ); CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_RUN); pq_insert(d, &(obj->msg_wait_q), _bh, NULL, &(ex->list), is_higher_priority); notify_bk_thread(obj); } static u8 pop_front_pending_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex **msg) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_msg = NULL; (*msg) = NULL; if (pq_pop(d, &(obj->msg_pend_q), &new_msg, _first, _bh)) { (*msg) = (struct phl_dispr_msg_ex *)new_msg; return true; } else { return false; } } static void push_back_pending_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { void *d = phl_to_drvpriv(obj->phl_info); SET_STATUS_FLAG(ex->status, MSG_STATUS_ENQ); CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_RUN); if(TEST_STATUS_FLAG(ex->status, MSG_STATUS_CLR_SNDR_MSG_IF_PENDING)) SET_CUR_PENDING_EVT(obj, MSG_MDL_ID_FIELD(ex->msg.msg_id), MSG_EVT_ID_FIELD(ex->msg.msg_id)); pq_push(d, &(obj->msg_pend_q), &(ex->list), _tail, _bh); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: remain cnt(%d)\n", __FUNCTION__, obj->msg_pend_q.cnt); } static void clear_pending_msg(struct cmd_dispatcher *obj) { struct phl_dispr_msg_ex *ex = NULL; if(!TEST_STATUS_FLAG(obj->status, DISPR_CLR_PEND_MSG)) return; CLEAR_STATUS_FLAG(obj->status, DISPR_CLR_PEND_MSG); while (pop_front_pending_msg(obj, &ex)) { if (IS_DISPR_CTRL(MSG_EVT_ID_FIELD(ex->msg.msg_id))) insert_msg_by_priority(obj, ex); else push_back_wait_msg(obj, ex); } } static void clear_waiting_msg(struct cmd_dispatcher *obj) { struct phl_dispr_msg_ex *ex = NULL; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: remain cnt(%d)\n", __FUNCTION__, obj->msg_idle_q.cnt); while(obj->msg_idle_q.cnt != MAX_PHL_MSG_NUM) { while (pop_front_pending_msg(obj, &ex)) push_back_wait_msg(obj, ex); while (pop_front_wait_msg(obj, &ex)) push_back_idle_msg(obj, ex); } } static bool is_special_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { u8 mdl_id = MSG_MDL_ID_FIELD(ex->msg.msg_id); u16 evt = MSG_EVT_ID_FIELD(ex->msg.msg_id); if (TEST_STATUS_FLAG(obj->status, DISPR_CANNOT_IO)) { if ( IS_EXCL_MDL(obj, mdl_id) || evt == MSG_EVT_DEV_CANNOT_IO || evt == MSG_EVT_DEV_RESUME_IO || evt == MSG_EVT_PHY_ON || evt == MSG_EVT_PHY_IDLE) return true; } return false; } static bool is_msg_canceled(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { u16 pending_evt = GET_CUR_PENDING_EVT(obj, MSG_MDL_ID_FIELD(ex->msg.msg_id)); if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED) || TEST_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL)) return true; if (pending_evt != MSG_EVT_MAX && pending_evt != MSG_EVT_ID_FIELD(ex->msg.msg_id)) { SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "msg canceled, cur pending evt(%d)\n", pending_evt); return true; } if (TEST_STATUS_FLAG(obj->status, DISPR_SHALL_STOP)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "msg canceled due to SHALL STOP status\n"); SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_CANNOT_IO); SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); return true; } if (TEST_STATUS_FLAG(obj->status, DISPR_CANNOT_IO)) { if( is_special_msg(obj, ex)) { SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_CANNOT_IO); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "special msg found, still sent with CANNOT IO flag set\n"); } else if (!TEST_STATUS_FLAG(ex->status, MSG_STATUS_PENDING_DURING_CANNOT_IO)) { SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_CANNOT_IO); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "msg canceled due to CANNOT IO status\n"); return true; } else { SET_STATUS_FLAG(ex->status, MSG_STATUS_PENDING); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "msg pending due to CANNOT IO status\n"); } } return false; } void init_dispr_msg_pool(struct cmd_dispatcher *obj) { u8 i = 0; void *d = phl_to_drvpriv(obj->phl_info); if (TEST_STATUS_FLAG(obj->status, DISPR_MSGQ_INIT)) return; pq_init(d, &(obj->msg_idle_q)); pq_init(d, &(obj->msg_wait_q)); pq_init(d, &(obj->msg_pend_q)); _os_mem_set(d, obj->msg_ex_pool, 0, sizeof(struct phl_dispr_msg_ex) * MAX_PHL_MSG_NUM); for (i = 0; i < MAX_PHL_MSG_NUM; i++) { obj->msg_ex_pool[i].idx = i; push_back_idle_msg(obj, &(obj->msg_ex_pool[i])); } SET_STATUS_FLAG(obj->status, DISPR_MSGQ_INIT); } void deinit_dispr_msg_pool(struct cmd_dispatcher *obj) { void *d = phl_to_drvpriv(obj->phl_info); if (!TEST_STATUS_FLAG(obj->status, DISPR_MSGQ_INIT)) return; CLEAR_STATUS_FLAG(obj->status, DISPR_MSGQ_INIT); pq_deinit(d, &(obj->msg_idle_q)); pq_deinit(d, &(obj->msg_wait_q)); pq_deinit(d, &(obj->msg_pend_q)); } void cancel_msg(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { void *d = phl_to_drvpriv(obj->phl_info); /* zero bitmap to ensure msg would not be forward to * any modules after cancel. * */ _reset_bitmap(d, ex->premap, MODL_MASK_LEN); _reset_bitmap(d, ex->postmap, MODL_MASK_LEN); SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); } void cancel_running_msg(struct cmd_dispatcher *obj) { u8 i = 0; for (i = 0; i < MAX_PHL_MSG_NUM;i++) { if(TEST_STATUS_FLAG(obj->msg_ex_pool[i].status, MSG_STATUS_RUN)) cancel_msg(obj, &(obj->msg_ex_pool[i])); } } void set_msg_bitmap(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, u8 mdl_id) { void *d = phl_to_drvpriv(obj->phl_info); /* ensure mandatory & wifi role module recv all msg*/ _os_mem_cpy(d, ex->premap, obj->bitmap, MODL_MASK_LEN); _os_mem_cpy(d, ex->postmap, obj->bitmap, MODL_MASK_LEN); if(_chk_bitmap_bit(obj->bitmap, mdl_id)) { _add_bitmap_bit(ex->premap, &mdl_id, 1); _add_bitmap_bit(ex->postmap, &mdl_id, 1); } //_print_bitmap(ex->premap); } void set_msg_custom_bitmap(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, enum phl_msg_opt opt, u8 *id_arr, u32 len, u8 mdl_id) { void *d = phl_to_drvpriv(obj->phl_info); if (opt & MSG_OPT_SKIP_NOTIFY_OPT_MDL) { _os_mem_cpy(d, ex->premap, obj->basemap, MODL_MASK_LEN); _os_mem_cpy(d, ex->postmap, obj->basemap, MODL_MASK_LEN); } if (opt & MSG_OPT_BLIST_PRESENT) { _clr_bitmap_bit(ex->premap, id_arr, len); _clr_bitmap_bit(ex->postmap, id_arr, len); } else { _add_bitmap_bit(ex->premap, id_arr, len); _add_bitmap_bit(ex->postmap, id_arr, len); } if(_chk_bitmap_bit(obj->bitmap, mdl_id)) { _add_bitmap_bit(ex->premap, &mdl_id, 1); _add_bitmap_bit(ex->postmap, &mdl_id, 1); } } u8 *get_msg_bitmap(struct phl_dispr_msg_ex *ex) { if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_PRE_PHASE)) { SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_PRE_PHASE); return ex->premap; } else { CLEAR_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_PRE_PHASE); return ex->postmap; } } void init_dispr_mdl_mgnt_info(struct cmd_dispatcher *obj) { u8 i = 0; for (i = 0; i < PHL_MDL_ID_MAX; i++) SET_CUR_PENDING_EVT(obj, i, MSG_EVT_MAX); } static u8 pop_front_idle_req(struct cmd_dispatcher *obj, struct phl_cmd_token_req_ex **req) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_req = NULL; (*req) = NULL; if (pq_pop(d, &(obj->token_req_idle_q), &new_req, _first, _bh)) { (*req) = (struct phl_cmd_token_req_ex*)new_req; (*req)->status = 0; _os_mem_set(d, &((*req)->req), 0, sizeof(struct phl_cmd_token_req)); _os_mem_set(d, &((*req)->add_req_info), 0, sizeof(struct phl_token_op_info)); _os_mem_set(d, &((*req)->free_req_info), 0, sizeof(struct phl_token_op_info)); return true; } else { return false; } } static void push_back_idle_req(struct cmd_dispatcher *obj, struct phl_cmd_token_req_ex *req) { void *d = phl_to_drvpriv(obj->phl_info); req->status = 0; SET_CUR_PENDING_EVT(obj, req->req.module_id, MSG_EVT_MAX); pq_push(d, &(obj->token_req_idle_q), &(req->list), _tail, _bh); } static u8 pop_front_wait_req(struct cmd_dispatcher *obj, struct phl_cmd_token_req_ex **req) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_req = NULL; (*req) = NULL; if (pq_pop(d, &(obj->token_req_wait_q), &new_req, _first, _bh)) { (*req) = (struct phl_cmd_token_req_ex*)new_req; SET_STATUS_FLAG((*req)->status, REQ_STATUS_PREPARE); CLEAR_STATUS_FLAG((*req)->status, REQ_STATUS_ENQ); return true; } else { return false; } } static void push_back_wait_req(struct cmd_dispatcher *obj, struct phl_cmd_token_req_ex *req) { void *d = phl_to_drvpriv(obj->phl_info); pq_push(d, &(obj->token_req_wait_q), &(req->list), _tail, _bh); SET_STATUS_FLAG(req->status, REQ_STATUS_ENQ); } static void clear_wating_req(struct cmd_dispatcher *obj) { struct phl_cmd_token_req_ex *ex = NULL; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: remain cnt(%d)\n", __FUNCTION__, obj->token_req_idle_q.cnt); while(obj->token_req_idle_q.cnt != MAX_CMD_REQ_NUM) { while (pop_front_wait_req(obj, &ex)) { ex->req.abort(obj, ex->req.priv); push_back_idle_req(obj, ex); } } } void deregister_cur_cmd_req(struct cmd_dispatcher *obj, u8 notify) { struct phl_cmd_token_req *req = NULL; void *d = phl_to_drvpriv(obj->phl_info); u8 i = 0; struct phl_dispr_msg_ex *ex = NULL; if (obj->cur_cmd_req) { req = &(obj->cur_cmd_req->req); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id(%d), status(%d)\n", __FUNCTION__, req->module_id, obj->cur_cmd_req->status); CLEAR_STATUS_FLAG(obj->cur_cmd_req->status, REQ_STATUS_RUN); for (i = 0; i < MAX_PHL_MSG_NUM; i++) { ex = &(obj->msg_ex_pool[i]); if (req->module_id != MSG_MDL_ID_FIELD(ex->msg.msg_id)) continue; CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_OWNER_REQ); cancel_msg(obj, ex); if(TEST_STATUS_FLAG(ex->status, MSG_STATUS_PENDING)) { dispr_clr_pending_msg((void*)obj); /* inserted pending msg from this sepecific sender back to wait Q before abort notify * would guarantee msg sent in abort notify is exactly last msg from this sender * */ clear_pending_msg(obj); } } if (notify == true) { SET_STATUS_FLAG(obj->cur_cmd_req->status, REQ_STATUS_LAST_PERMIT); req->abort(obj, req->priv); CLEAR_STATUS_FLAG(obj->cur_cmd_req->status, REQ_STATUS_LAST_PERMIT); } #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ SET_MDL_HANDLE(obj, obj->cur_cmd_req->req.module_id, NULL); #endif push_back_idle_req(obj, obj->cur_cmd_req); _os_atomic_set(d, &(obj->token_cnt), _os_atomic_read(d, &(obj->token_cnt))-1); } obj->cur_cmd_req = NULL; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); } u8 register_cur_cmd_req(struct cmd_dispatcher *obj, struct phl_cmd_token_req_ex *req) { void *d = phl_to_drvpriv(obj->phl_info); enum phl_mdl_ret_code ret = MDL_RET_SUCCESS; SET_STATUS_FLAG(req->status, REQ_STATUS_RUN); CLEAR_STATUS_FLAG(req->status, REQ_STATUS_PREPARE); obj->cur_cmd_req = req; _os_atomic_set(d, &(obj->token_cnt), _os_atomic_read(d, &(obj->token_cnt))+1); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id(%d)\n", __FUNCTION__, obj->cur_cmd_req->req.module_id); ret = obj->cur_cmd_req->req.acquired((void*)obj, obj->cur_cmd_req->req.priv); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, ret(%d)\n", __FUNCTION__, ret); if (ret == MDL_RET_FAIL) { deregister_cur_cmd_req(obj, false); return false; } else { #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ SET_MDL_HANDLE(obj, req->req.module_id, req); #endif return true; } } void cancel_all_cmd_req(struct cmd_dispatcher *obj) { u8 i = 0; struct phl_cmd_token_req_ex* req_ex = NULL; for (i = 0; i < MAX_CMD_REQ_NUM;i++) { req_ex = &(obj->token_req_ex_pool[i]); if (req_ex->status) SET_STATUS_FLAG(req_ex->status, REQ_STATUS_CANCEL); } } void init_cmd_req_pool(struct cmd_dispatcher *obj) { u8 i = 0; void *d = phl_to_drvpriv(obj->phl_info); if (TEST_STATUS_FLAG(obj->status, DISPR_REQ_INIT)) return; pq_init(d, &(obj->token_req_wait_q)); pq_init(d, &(obj->token_req_idle_q)); pq_init(d, &(obj->token_op_q)); _os_mem_set(d, obj->token_req_ex_pool, 0, sizeof(struct phl_cmd_token_req_ex) * MAX_CMD_REQ_NUM); for (i = 0; i < MAX_CMD_REQ_NUM;i++) { obj->token_req_ex_pool[i].idx = i; pq_push(d, &(obj->token_req_idle_q), &(obj->token_req_ex_pool[i].list), _tail, _bh); } SET_STATUS_FLAG(obj->status, DISPR_REQ_INIT); } void deinit_cmd_req_pool(struct cmd_dispatcher *obj) { void *d = phl_to_drvpriv(obj->phl_info); CLEAR_STATUS_FLAG(obj->status, DISPR_REQ_INIT); pq_deinit(d, &(obj->token_req_wait_q)); pq_deinit(d, &(obj->token_req_idle_q)); pq_deinit(d, &(obj->token_op_q)); } u8 chk_module_ops(struct phl_bk_module_ops *ops) { if (ops == NULL || ops->init == NULL || ops->deinit == NULL || ops->msg_hdlr == NULL || ops->set_info == NULL || ops->query_info == NULL || ops->start == NULL || ops->stop == NULL) return false; return true; } u8 chk_cmd_req_ops(struct phl_cmd_token_req *req) { if (req == NULL || req->module_id < PHL_FG_MDL_START || req->abort == NULL || req->acquired == NULL || req->msg_hdlr == NULL || req->set_info == NULL || req->query_info == NULL) return false; return true; } static u8 pop_front_token_op_info(struct cmd_dispatcher *obj, struct phl_token_op_info **op_info) { void *d = phl_to_drvpriv(obj->phl_info); _os_list *new_info = NULL; (*op_info) = NULL; if (pq_pop(d, &(obj->token_op_q), &new_info, _first, _bh)) { (*op_info) = (struct phl_token_op_info *)new_info; return true; } else { return false; } } static u8 push_back_token_op_info(struct cmd_dispatcher *obj, struct phl_token_op_info *op_info, enum token_op_type type, u8 data) { void *d = phl_to_drvpriv(obj->phl_info); _os_spinlockfg sp_flags; _os_spinlock(d, &obj->token_op_q_lock, _bh, &sp_flags); if (op_info->used == true) { _os_spinunlock(d, &obj->token_op_q_lock, _bh, &sp_flags); return false; } op_info->used = true; op_info->type = type; op_info->data = data; _os_spinunlock(d, &obj->token_op_q_lock, _bh, &sp_flags); pq_push(d, &(obj->token_op_q), &(op_info->list), _tail, _bh); notify_bk_thread(obj); return true; } void _handle_token_op_info(struct cmd_dispatcher *obj, struct phl_token_op_info *op_info) { struct phl_cmd_token_req_ex *req_ex = NULL; void *d = phl_to_drvpriv(obj->phl_info); switch (op_info->type) { case TOKEN_OP_RENEW_CMD_REQ: /* fall through*/ case TOKEN_OP_ADD_CMD_REQ: dispr_process_token_req(obj); break; case TOKEN_OP_FREE_CMD_REQ: if (op_info->data >= MAX_CMD_REQ_NUM) return; req_ex = &(obj->token_req_ex_pool[op_info->data]); if (!TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_RUN)) break; deregister_cur_cmd_req(obj, false); dispr_process_token_req(obj); break; case TOKEN_OP_CANCEL_CMD_REQ: if (op_info->data >= MAX_CMD_REQ_NUM) return; req_ex = &(obj->token_req_ex_pool[op_info->data]); SET_STATUS_FLAG(req_ex->status, REQ_STATUS_CANCEL); if (TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_ENQ)) { pq_del_node(d, &(obj->token_req_wait_q), &(req_ex->list), _bh); /* * Call command abort handle, abort handle * should decide it has been acquired or not. */ req_ex->req.abort(obj, req_ex->req.priv); push_back_idle_req(obj, req_ex); } else if (TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_RUN)){ deregister_cur_cmd_req(obj, true); dispr_process_token_req(obj); } break; default: break; } } void token_op_hanler(struct cmd_dispatcher *obj) { struct phl_token_op_info *info = NULL; while (pop_front_token_op_info(obj, &info)) { _handle_token_op_info(obj, info); info->used = false; } } static u8 dispr_enqueue_token_op_info(struct cmd_dispatcher *obj, struct phl_token_op_info *op_info, enum token_op_type type, u8 data) { return push_back_token_op_info(obj, op_info, type, data); } u8 bk_module_init(struct cmd_dispatcher *obj, struct phl_bk_module *module) { if (TEST_STATUS_FLAG(module->status, MDL_INIT)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s module_id:%d already init\n", __FUNCTION__, module->id); return false; } if (module->ops.init((void*)obj->phl_info, (void*)obj, &(module->priv)) == MDL_RET_SUCCESS) { SET_STATUS_FLAG(module->status, MDL_INIT); return true; } else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s fail module_id: %d \n", __FUNCTION__, module->id); return false; } } void bk_module_deinit(struct cmd_dispatcher *obj, struct phl_bk_module *module) { if (TEST_STATUS_FLAG(module->status, MDL_INIT)) module->ops.deinit((void*)obj, module->priv); CLEAR_STATUS_FLAG(module->status, MDL_INIT); } u8 bk_module_start(struct cmd_dispatcher *obj, struct phl_bk_module *module) { if (!TEST_STATUS_FLAG(module->status, MDL_INIT) || TEST_STATUS_FLAG(module->status, MDL_STARTED)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s module_id:%d already start\n", __FUNCTION__, module->id); return false; } if (module->ops.start((void*)obj, module->priv) == MDL_RET_SUCCESS) { SET_STATUS_FLAG(module->status, MDL_STARTED); #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ SET_MDL_HANDLE(obj, module->id, module); #endif return true; } else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s fail module_id: %d \n", __FUNCTION__, module->id); return false; } } u8 bk_module_stop(struct cmd_dispatcher *obj, struct phl_bk_module *module) { if (!TEST_STATUS_FLAG(module->status, MDL_STARTED)) return false; CLEAR_STATUS_FLAG(module->status, MDL_STARTED); #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ SET_MDL_HANDLE(obj, module->id, NULL); #endif if (module->ops.stop((void*)obj, module->priv) == MDL_RET_SUCCESS) { return true; } else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s fail module_id: %d \n", __FUNCTION__, module->id); return false; } } void cur_req_hdl(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { struct phl_cmd_token_req_ex *cur_req = obj->cur_cmd_req; if (cur_req == NULL) return; if (!TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_RUN) || TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_CANCEL)) return; if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_FOR_ABORT)) return; cur_req->req.msg_hdlr((void*)obj, cur_req->req.priv, &(ex->msg)); } void notify_msg_fail(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, enum phl_mdl_ret_code ret) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); SET_STATUS_FLAG(ex->status, MSG_STATUS_FAIL); SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_FAIL); if (ret == MDL_RET_CANNOT_IO) SET_MSG_INDC_FIELD(ex->msg.msg_id, MSG_INDC_CANNOT_IO); if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_OWNER_BK_MDL) && (IS_DISPR_CTRL(MSG_MDL_ID_FIELD(ex->msg.msg_id)) || _chk_bitmap_bit(obj->bitmap, ex->module->id))) { ex->module->ops.msg_hdlr(obj, ex->module->priv, &(ex->msg)); } if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_OWNER_REQ)) { cur_req_hdl(obj, ex); } } enum phl_mdl_ret_code feed_mdl_msg(struct cmd_dispatcher *obj, struct phl_bk_module *mdl, struct phl_dispr_msg_ex *ex) { enum phl_mdl_ret_code ret = MDL_RET_FAIL; u8 *bitmap = NULL; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_, "%s, id:%d \n", __FUNCTION__, mdl->id); ret = mdl->ops.msg_hdlr(obj, mdl->priv, &(ex->msg)); if (ret == MDL_RET_FAIL || ret == MDL_RET_CANNOT_IO) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "id:%d evt:0x%x fail\n", mdl->id, ex->msg.msg_id); ex->msg.rsvd[0] = mdl; notify_msg_fail(obj, ex, ret); } else if (ret == MDL_RET_PENDING) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "id:%d evt:0x%x pending\n", mdl->id, ex->msg.msg_id); SET_STATUS_FLAG(ex->status, MSG_STATUS_PENDING); } else { if (MSG_INDC_FIELD(ex->msg.msg_id) & MSG_INDC_PRE_PHASE) bitmap = ex->premap; else bitmap = ex->postmap; _clr_bitmap_bit(bitmap, &(mdl->id), 1); } return ret; } void msg_pre_phase_hdl(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { s8 i = 0; void *d = phl_to_drvpriv(obj->phl_info); struct phl_bk_module *mdl = NULL; _os_list *node = NULL; struct phl_queue *q = NULL; enum phl_mdl_ret_code ret = MDL_RET_FAIL; u8 owner_id = (ex->module)?(ex->module->id):(PHL_MDL_ID_MAX); enum phl_bk_module_priority priority = PHL_MDL_PRI_MAX; if (owner_id <= PHL_BK_MDL_END) priority = _get_mdl_priority(owner_id); for (i = PHL_MDL_PRI_MAX - 1 ; i >= PHL_MDL_PRI_ROLE ; i--) { #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ ret = run_self_def_seq(obj, ex, i, true); if (STOP_DISPATCH_MSG(ret)) return; #endif if (priority == i && _chk_bitmap_bit(ex->premap, owner_id)) { ret = feed_mdl_msg(obj, ex->module, ex); if (STOP_DISPATCH_MSG(ret)) return; } q = &(obj->module_q[(u8)i]); if (pq_get_front(d, q, &node, _bh) == false) continue; do { mdl = (struct phl_bk_module*)node; if (!_chk_bitmap_bit(ex->premap, mdl->id) || !TEST_STATUS_FLAG(mdl->status, MDL_STARTED)) continue; ret = feed_mdl_msg(obj, mdl, ex); if (STOP_DISPATCH_MSG(ret)) return; } while(pq_get_next(d, q, node, &node, _bh)); } } void msg_post_phase_hdl(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { s8 i = 0; void *d = phl_to_drvpriv(obj->phl_info); struct phl_bk_module *mdl = NULL; _os_list *node = NULL; struct phl_queue *q = NULL; enum phl_mdl_ret_code ret = MDL_RET_FAIL; u8 owner_id = (ex->module)?(ex->module->id):(PHL_MDL_ID_MAX); enum phl_bk_module_priority priority = PHL_MDL_PRI_MAX; if (owner_id <= PHL_BK_MDL_END) priority = _get_mdl_priority(owner_id); for (i = PHL_MDL_PRI_ROLE ; i < PHL_MDL_PRI_MAX ; i++) { #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ ret = run_self_def_seq(obj, ex, i, false); if (STOP_DISPATCH_MSG(ret)) return; #endif if (priority == i && _chk_bitmap_bit(ex->postmap, owner_id)) { ret = feed_mdl_msg(obj, ex->module, ex); if (STOP_DISPATCH_MSG(ret)) return; } q = &(obj->module_q[(u8)i]); if (pq_get_tail(d, q, &node, _bh) == false) continue; do { mdl = (struct phl_bk_module*)node; if (!_chk_bitmap_bit(ex->postmap, mdl->id)|| !TEST_STATUS_FLAG(mdl->status, MDL_STARTED)) continue; ret = feed_mdl_msg(obj, mdl, ex); if (STOP_DISPATCH_MSG(ret)) return; } while(pq_get_prev(d, q, node, &node, _bh)); } } u8 get_cur_cmd_req_id(struct cmd_dispatcher *obj, u32 *req_status) { struct phl_cmd_token_req_ex *cur_req = obj->cur_cmd_req; if(req_status) *req_status = 0; if (cur_req == NULL ) return (u8)PHL_MDL_ID_MAX; if(req_status) *req_status = cur_req->status; if(!TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_RUN) || TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_CANCEL)) return (u8)PHL_MDL_ID_MAX; else return cur_req->req.module_id; } #define MSG_REDIRECT_CHK(_ex) \ if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_FAIL)|| \ TEST_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL)) \ goto recycle;\ if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_PENDING)) \ goto reschedule; void msg_dispatch(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { u8 *bitmap = get_msg_bitmap(ex); void *d = phl_to_drvpriv(obj->phl_info); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_, "%s, msg_id:0x%x status: 0x%x\n", __FUNCTION__, ex->msg.msg_id, ex->status); MSG_REDIRECT_CHK(ex); _notify_dispr_controller(obj, ex); MSG_REDIRECT_CHK(ex); if ((MSG_INDC_FIELD(ex->msg.msg_id) & MSG_INDC_PRE_PHASE) && _is_bitmap_empty(d, bitmap) == false) msg_pre_phase_hdl(obj, ex); MSG_REDIRECT_CHK(ex); if (_is_bitmap_empty(d, bitmap)) { /* pre protocol phase done, switch to post protocol phase*/ CLEAR_STATUS_FLAG(ex->status, MSG_STATUS_PRE_PHASE); bitmap = get_msg_bitmap(ex); } else { PHL_ERR("%s, invalid bitmap state, msg status:0x%x \n", __FUNCTION__, ex->status); SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); goto recycle; } if (_is_bitmap_empty(d, bitmap) == false) msg_post_phase_hdl(obj, ex); MSG_REDIRECT_CHK(ex); if (_is_bitmap_empty(d, bitmap)) { /* post protocol phase done */ cur_req_hdl(obj, ex); goto recycle; } else { PHL_ERR("%s, invalid bitmap state, msg status:0x%x \n", __FUNCTION__, ex->status); SET_STATUS_FLAG(ex->status, MSG_STATUS_CANCEL); goto recycle; } reschedule: PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, msg:0x%x reschedule \n", __FUNCTION__, ex->msg.msg_id); if(TEST_STATUS_FLAG(ex->status, MSG_STATUS_PENDING)) push_back_pending_msg(obj, ex); else push_back_wait_msg(obj, ex); return; recycle: PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_, "%s, msg:0x%x recycle \n", __FUNCTION__, ex->msg.msg_id); push_back_idle_msg(obj, ex); } void dispr_thread_loop_hdl(struct cmd_dispatcher *obj) { struct phl_dispr_msg_ex *ex = NULL; /* check pending msg need in advance. * if pending msg is not empty before while loop breaks, * these msg would be cleared in deinit_dispr_msg_pool. */ clear_pending_msg(obj); /* token op Q in advance. * if req wait Q is not empty before while loop breaks, * these msg would be cleared in deinit_cmd_req_pool. */ token_op_hanler(obj); if (pop_front_wait_msg(obj, &ex)) { if (is_msg_canceled(obj, ex)) { push_back_idle_msg(obj, ex); return; } /* ensure all modules set in msg bitmap exists in cur dispatcher*/ _and_bitmaps(obj->bitmap, ex->premap, MODL_MASK_LEN); _and_bitmaps(obj->bitmap, ex->postmap, MODL_MASK_LEN); msg_dispatch(obj, ex); } } void dispr_thread_leave_hdl(struct cmd_dispatcher *obj) { deregister_cur_cmd_req(obj, true); /* clear remaining pending & waiting msg */ clear_waiting_msg(obj); /* pop out all waiting cmd req and notify abort. */ clear_wating_req(obj); } int background_thread_hdl(void *param) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)param; void *d = phl_to_drvpriv(obj->phl_info); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s enter\n", __FUNCTION__); while (!_os_thread_check_stop(d, &(obj->bk_thread))) { _os_sema_down(d, &obj->msg_q_sema); if(_os_thread_check_stop(d, &(obj->bk_thread))) break; dispr_thread_loop_hdl(obj); } dispr_thread_leave_hdl(obj); _os_thread_wait_stop(d, &(obj->bk_thread)); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s down\n", __FUNCTION__); return 0; } u8 search_mdl(void *d, void *mdl, void *priv) { enum phl_module_id id = *(enum phl_module_id *)priv; struct phl_bk_module *module = NULL; module = (struct phl_bk_module *)mdl; if (module->id == id) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s :: id %d\n", __FUNCTION__, id); return true; } else return false; } u8 get_module_by_id(struct cmd_dispatcher *obj, enum phl_module_id id, struct phl_bk_module **mdl) { void *d = phl_to_drvpriv(obj->phl_info); u8 i = 0; _os_list *node = NULL; if (mdl == NULL) return false; if (IS_DISPR_CTRL(id)) { if (!TEST_STATUS_FLAG(obj->status, DISPR_CTRL_PRESENT)) return false; *mdl = &(obj->controller); return true; } if (!_chk_bitmap_bit(obj->bitmap, id)) return false; for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if(pq_search_node(d, &(obj->module_q[i]), &node, _bh, false, &id, search_mdl)) { *mdl = (struct phl_bk_module*)node; return true; } } *mdl = NULL; return false; } enum rtw_phl_status phl_dispr_get_idx(void *dispr, u8 *idx) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; if (dispr == NULL) return RTW_PHL_STATUS_FAILURE; if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || idx == NULL) return RTW_PHL_STATUS_FAILURE; *idx = obj->idx; return RTW_PHL_STATUS_SUCCESS; } /* Each dispr has a controller. * A dispr controller is designed for phl instance to interact with dispr modules that are belonged to a specific hw band, * phl instance can perform follwing actions via dedicated controller: * 1. allow (phl status/non-dispr phl modules) to monitor & drop msg * 2. allow dispr modules, that are belonged to same dispr, to sequentially communicate with phl instance & call phl api, * and also allow (phl status/non-dispr phl modules) to notify dispr by hw band. * *Note* * 1. when cmd dispatch engine is in solo thread mode (each dispr has its own dedicated thread). * phl instance might receive msg from different dispr simutaneously and * currently using semaphore (dispr_ctrl_sema) to prevent multi-thread condition. * 2. when cmd dispatch engine is in share thread mode, msg from different dispr would pass to controller sequentially. * PS: * phl instance: means phl_info_t, which include phl mgnt status & non-dispr phl modules * dispr modules: all existing background & foreground modules. * non-dispr phl module : Data path (TX/Rx), etc * phl mgnt status : stop/surprise remove/cannot io */ static enum rtw_phl_status _register_dispr_controller(struct cmd_dispatcher *obj) { struct phl_bk_module *ctrl = &(obj->controller); dispr_ctrl_hook_ops(obj, &(ctrl->ops)); ctrl->id = PHL_MDL_PHY_MGNT; if(bk_module_init(obj, &(obj->controller)) == true) return RTW_PHL_STATUS_SUCCESS; else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s(): fail \n", __func__); return RTW_PHL_STATUS_FAILURE; } } static void _deregister_dispr_controller(struct cmd_dispatcher *obj) { bk_module_deinit(obj, &(obj->controller)); } static enum rtw_phl_status _start_dispr_controller(struct cmd_dispatcher *obj) { if (bk_module_start(obj, &(obj->controller)) == true) { SET_STATUS_FLAG(obj->status, DISPR_CTRL_PRESENT); return RTW_PHL_STATUS_SUCCESS; } else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s(): fail \n", __func__); return RTW_PHL_STATUS_FAILURE; } } static enum rtw_phl_status _stop_dispr_controller(struct cmd_dispatcher *obj) { CLEAR_STATUS_FLAG(obj->status, DISPR_CTRL_PRESENT); if (bk_module_stop(obj, &(obj->controller)) == true) return RTW_PHL_STATUS_SUCCESS; else { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s(): fail \n", __func__); return RTW_PHL_STATUS_FAILURE; } } void _notify_dispr_controller(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex) { if (!TEST_STATUS_FLAG(obj->status, DISPR_CTRL_PRESENT)) return; #ifdef CONFIG_CMD_DISP_SOLO_MODE dispr_ctrl_sema_down(obj->phl_info); #endif feed_mdl_msg(obj, &(obj->controller), ex); #ifdef CONFIG_CMD_DISP_SOLO_MODE dispr_ctrl_sema_up(obj->phl_info); #endif } void dispr_thread_stop_prior_hdl(struct cmd_dispatcher *obj) { CLEAR_STATUS_FLAG(obj->status, DISPR_STARTED); _stop_dispr_controller(obj); cancel_all_cmd_req(obj); cancel_running_msg(obj); } void dispr_thread_stop_post_hdl(struct cmd_dispatcher *obj) { void *d = phl_to_drvpriv(obj->phl_info); /* have to wait for bk thread ends before deinit msg & req*/ deinit_dispr_msg_pool(obj); deinit_cmd_req_pool(obj); _os_atomic_set(d, &(obj->token_cnt), 0); _os_sema_free(d, &(obj->msg_q_sema)); } enum rtw_phl_status dispr_init(struct phl_info_t *phl_info, void **dispr, u8 idx) { struct cmd_dispatcher *obj = NULL; void *d = phl_to_drvpriv(phl_info); u8 i = 0; (*dispr) = NULL; obj = (struct cmd_dispatcher *)_os_mem_alloc(d, sizeof(struct cmd_dispatcher)); if (obj == NULL) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, alloc fail\n", __FUNCTION__); return RTW_PHL_STATUS_RESOURCE; } obj->phl_info = phl_info; obj->idx = idx; _os_atomic_set(d, &(obj->token_cnt), 0); for (i = 0 ; i < PHL_MDL_PRI_MAX; i++) pq_init(d, &(obj->module_q[i])); (*dispr) = (void*)obj; _os_spinlock_init(d, &(obj->token_op_q_lock)); SET_STATUS_FLAG(obj->status, DISPR_INIT); SET_STATUS_FLAG(obj->status, DISPR_NOTIFY_IDLE); _register_dispr_controller(obj); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, size dispr(%d), msg_ex(%d), req_ex(%d) \n", __FUNCTION__, (int)sizeof(struct cmd_dispatcher), (int)sizeof(struct phl_dispr_msg_ex), (int)sizeof(struct phl_cmd_token_req_ex)); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_deinit(struct phl_info_t *phl, void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); u8 i = 0; if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT)) return RTW_PHL_STATUS_SUCCESS; dispr_stop(dispr); _deregister_dispr_controller(obj); for (i = 0 ; i < PHL_MDL_PRI_MAX; i++) pq_deinit(d, &(obj->module_q[i])); _os_spinlock_free(d, &(obj->token_op_q_lock)); _os_mem_free(d, obj, sizeof(struct cmd_dispatcher)); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_start(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); if (TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return RTW_PHL_STATUS_UNEXPECTED_ERROR; init_dispr_msg_pool(obj); init_cmd_req_pool(obj); init_dispr_mdl_mgnt_info(obj); _os_mem_set(d, &(obj->renew_req_info), 0, sizeof(struct phl_token_op_info)); _os_sema_init(d, &(obj->msg_q_sema), 0); CLEAR_EXCL_MDL(obj); if (disp_eng_is_solo_thread_mode(obj->phl_info)) { _os_thread_init(d, &(obj->bk_thread), background_thread_hdl, obj, "dispr_solo_thread"); _os_thread_schedule(d, &(obj->bk_thread)); } SET_STATUS_FLAG(obj->status, DISPR_STARTED); _start_dispr_controller(obj); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } bool is_dispr_started(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; if (TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return true; return false; } enum rtw_phl_status dispr_stop(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return RTW_PHL_STATUS_UNEXPECTED_ERROR; dispr_thread_stop_prior_hdl(obj); if (disp_eng_is_solo_thread_mode(obj->phl_info)) { _os_thread_stop(d, &(obj->bk_thread)); _os_sema_up(d, &(obj->msg_q_sema)); _os_thread_deinit(d, &(obj->bk_thread)); } dispr_thread_stop_post_hdl(obj); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_register_module(void *dispr, enum phl_module_id id, struct phl_bk_module_ops *ops) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct phl_bk_module *module = NULL; u8 ret = true; enum phl_bk_module_priority priority = _get_mdl_priority(id); FUNCIN(); if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || priority == PHL_MDL_PRI_MAX || chk_module_ops(ops) == false || _chk_bitmap_bit(obj->bitmap, id) == true) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, register fail\n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } module = (struct phl_bk_module *)_os_mem_alloc(d, sizeof(struct phl_bk_module)); if (module == NULL) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, allocte fail\n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } module->id = id; _os_mem_cpy(d, &(module->ops), ops, sizeof(struct phl_bk_module_ops)); pq_push(d, &(obj->module_q[priority]), &(module->list), _tail, _bh); ret = bk_module_init(obj, module); if (ret == true && TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) { ret = bk_module_start(obj, module); if (ret == true) _add_bitmap_bit(obj->bitmap, &(module->id), 1); if (ret == true && priority != PHL_MDL_PRI_OPTIONAL) _add_bitmap_bit(obj->basemap, &(module->id), 1); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s id:%d, ret:%d\n",__FUNCTION__, id, ret); if (ret == true) { return RTW_PHL_STATUS_SUCCESS; } else { bk_module_deinit(obj, module); _os_mem_free(d, module, sizeof(struct phl_bk_module)); return RTW_PHL_STATUS_FAILURE; } } enum rtw_phl_status dispr_deregister_module(void *dispr, enum phl_module_id id) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct phl_bk_module *module = NULL; _os_list *mdl = NULL; enum rtw_phl_status phl_stat = RTW_PHL_STATUS_FAILURE; enum phl_bk_module_priority priority = _get_mdl_priority(id); FUNCIN(); if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || priority == PHL_MDL_PRI_MAX) return phl_stat; if(pq_search_node(d, &(obj->module_q[priority]), &mdl, _bh, true, &id, search_mdl)) { module = (struct phl_bk_module *)mdl; _clr_bitmap_bit(obj->bitmap, &(module->id), 1); _clr_bitmap_bit(obj->basemap, &(module->id), 1); bk_module_stop(obj, module); bk_module_deinit(obj, module); _os_mem_free(d, module, sizeof(struct phl_bk_module)); phl_stat = RTW_PHL_STATUS_SUCCESS; } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id: %d stat:%d\n", __FUNCTION__, id, phl_stat); return phl_stat; } enum rtw_phl_status dispr_module_init(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); _os_list *mdl = NULL; u8 i = 0; if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT)) return RTW_PHL_STATUS_FAILURE; for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if (pq_get_front(d, &(obj->module_q[i]), &mdl, _bh) == false) continue; do { bk_module_init(obj, (struct phl_bk_module *)mdl); } while(pq_get_next(d, &(obj->module_q[i]), mdl, &mdl, _bh)); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_module_deinit(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); _os_list *mdl = NULL; u8 i = 0; if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT)) return RTW_PHL_STATUS_FAILURE; for (i = 0; i < PHL_MDL_PRI_MAX; i++) { while (pq_pop(d, &(obj->module_q[i]), &mdl, _first, _bh)) { bk_module_deinit(obj, (struct phl_bk_module *)mdl); _os_mem_free(d, mdl, sizeof(struct phl_bk_module)); } } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_module_start(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); _os_list *mdl = NULL; struct phl_bk_module *module = NULL; u8 i = 0; u8 ret = false; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return RTW_PHL_STATUS_UNEXPECTED_ERROR; for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if (pq_get_front(d, &(obj->module_q[i]), &mdl, _bh) == false) continue; do { module = (struct phl_bk_module*)mdl; ret = bk_module_start(obj, module); if (ret == true) _add_bitmap_bit(obj->bitmap, &(module->id), 1); if (ret == true && i != PHL_MDL_PRI_OPTIONAL) _add_bitmap_bit(obj->basemap, &(module->id), 1); } while(pq_get_next(d, &(obj->module_q[i]), mdl, &mdl, _bh)); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); /*_print_bitmap(obj->bitmap);*/ return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_module_stop(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); _os_list *mdl = NULL; struct phl_bk_module *module = NULL; u8 i = 0; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return RTW_PHL_STATUS_UNEXPECTED_ERROR; for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if (pq_get_front(d, &(obj->module_q[i]), &mdl, _bh) == false) continue; do { module = (struct phl_bk_module *)mdl; _clr_bitmap_bit(obj->bitmap, &(module->id), 1); _clr_bitmap_bit(obj->basemap, &(module->id), 1); bk_module_stop(obj, module); } while(pq_get_next(d, &(obj->module_q[i]), mdl, &mdl, _bh)); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); /*_print_bitmap(obj->bitmap);*/ return RTW_PHL_STATUS_SUCCESS; } /** * dispr_get_cur_cmd_req -- background module can call this function to * check cmd dispatcher is idle to know the risk or conflict for the I/O. * @dispr: dispatcher handler, get from _disp_eng_get_dispr_by_idx * @handle: get current cmd request, NULL means cmd dispatcher is idle * return RTW_PHL_STATUS_SUCCESS means cmd dispatcher is busy and can get * current cmd request from handle parameter * return RTW_PHL_STATUS_FAILURE means cmd dispatcher is idle */ enum rtw_phl_status dispr_get_cur_cmd_req(void *dispr, void **handle) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; struct phl_cmd_token_req_ex *cur_req = NULL; enum rtw_phl_status phl_stat = RTW_PHL_STATUS_FAILURE; if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT|DISPR_STARTED) || handle == NULL) { phl_stat = RTW_PHL_STATUS_UNEXPECTED_ERROR; return phl_stat; } (*handle) = NULL; cur_req = obj->cur_cmd_req; if (cur_req == NULL || !TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_RUN) || TEST_STATUS_FLAG(cur_req->status, REQ_STATUS_CANCEL)) return phl_stat; *handle = (void *)cur_req; phl_stat = RTW_PHL_STATUS_SUCCESS; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_, "%s, req module id:%d phl_stat:%d\n", __FUNCTION__, cur_req->req.module_id, phl_stat); return phl_stat; } enum rtw_phl_status dispr_set_cur_cmd_info(void *dispr, struct phl_module_op_info *op_info) { void *handle = NULL; struct phl_cmd_token_req_ex *cmd_req = NULL; struct phl_cmd_token_req *req = NULL; if (RTW_PHL_STATUS_SUCCESS != dispr_get_cur_cmd_req(dispr, &handle)) return RTW_PHL_STATUS_FAILURE; cmd_req = (struct phl_cmd_token_req_ex *)handle; req = &(cmd_req->req); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d\n", __FUNCTION__, req->module_id); if (req->set_info(dispr, req->priv, op_info) == MDL_RET_SUCCESS) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_query_cur_cmd_info(void *dispr, struct phl_module_op_info *op_info) { void *handle = NULL; struct phl_cmd_token_req_ex *cmd_req = NULL; struct phl_cmd_token_req *req = NULL; if (RTW_PHL_STATUS_SUCCESS != dispr_get_cur_cmd_req(dispr, &handle)) return RTW_PHL_STATUS_FAILURE; cmd_req = (struct phl_cmd_token_req_ex *)handle; req = &(cmd_req->req); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_DEBUG_, "%s, id:%d\n", __FUNCTION__, req->module_id); if (req->query_info(dispr, req->priv, op_info) == MDL_RET_SUCCESS) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_get_bk_module_handle(void *dispr, enum phl_module_id id, void **handle) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); _os_list *mdl = NULL; enum rtw_phl_status phl_stat = RTW_PHL_STATUS_FAILURE; enum phl_bk_module_priority priority = _get_mdl_priority(id); if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || handle == NULL || priority == PHL_MDL_PRI_MAX || !_chk_bitmap_bit(obj->bitmap, id)) return phl_stat; (*handle) = NULL; if(pq_search_node(d, &(obj->module_q[priority]), &mdl, _bh, false, &id, search_mdl)) { (*handle) = mdl; phl_stat = RTW_PHL_STATUS_SUCCESS; } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d phl_stat:%d\n", __FUNCTION__, id, phl_stat); return phl_stat; } enum rtw_phl_status dispr_set_bk_module_info(void *dispr, void *handle, struct phl_module_op_info *op_info) { struct phl_bk_module *module = (struct phl_bk_module *)handle; struct phl_bk_module_ops *ops = &(module->ops); if (!TEST_STATUS_FLAG(module->status, MDL_INIT)) return RTW_PHL_STATUS_FAILURE; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d\n", __FUNCTION__, module->id); if (ops->set_info(dispr, module->priv, op_info) == MDL_RET_SUCCESS) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_query_bk_module_info(void *dispr, void *handle, struct phl_module_op_info *op_info) { struct phl_bk_module *module = (struct phl_bk_module *)handle; struct phl_bk_module_ops *ops = &(module->ops); if (!TEST_STATUS_FLAG(module->status, MDL_INIT)) return RTW_PHL_STATUS_FAILURE; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d\n", __FUNCTION__, module->id); if (ops->query_info(dispr, module->priv, op_info) == MDL_RET_SUCCESS) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_set_src_info(void *dispr, struct phl_msg *msg, struct phl_module_op_info *op_info) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; enum rtw_phl_status phl_stat = RTW_PHL_STATUS_FAILURE; u8 id = MSG_MDL_ID_FIELD(msg->msg_id); struct phl_cmd_token_req_ex *cur_req = obj->cur_cmd_req; enum phl_mdl_ret_code ret = MDL_RET_FAIL; struct phl_dispr_msg_ex *ex = (struct phl_dispr_msg_ex *)msg; u8 cur_req_id = get_cur_cmd_req_id(obj, NULL); if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || (!_chk_bitmap_bit(obj->bitmap, id) && cur_req_id != id)) return phl_stat; if (cur_req_id == id) { ret = cur_req->req.set_info(dispr, cur_req->req.priv, op_info); } else if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_OWNER_BK_MDL)) { ret = ex->module->ops.set_info(dispr, ex->module->priv, op_info); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d phl_stat:%d\n", __FUNCTION__, id, phl_stat); if (ret == MDL_RET_FAIL) return RTW_PHL_STATUS_FAILURE; else return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_query_src_info(void *dispr, struct phl_msg *msg, struct phl_module_op_info *op_info) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; enum rtw_phl_status phl_stat = RTW_PHL_STATUS_FAILURE; u8 id = MSG_MDL_ID_FIELD(msg->msg_id); struct phl_cmd_token_req_ex *cur_req = obj->cur_cmd_req; struct phl_dispr_msg_ex *ex = (struct phl_dispr_msg_ex *)msg; enum phl_mdl_ret_code ret = MDL_RET_FAIL; u8 cur_req_id = get_cur_cmd_req_id(obj, NULL); if (!TEST_STATUS_FLAG(obj->status, DISPR_INIT) || (!_chk_bitmap_bit(obj->bitmap, id) && cur_req_id != id)) return phl_stat; if (cur_req_id == id) { ret = cur_req->req.query_info(dispr, cur_req->req.priv, op_info); } else if (TEST_STATUS_FLAG(ex->status, MSG_STATUS_OWNER_BK_MDL)) { ret = ex->module->ops.query_info(dispr, ex->module->priv, op_info); } PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d phl_stat:%d\n", __FUNCTION__, id, phl_stat); if (ret == MDL_RET_FAIL) return RTW_PHL_STATUS_FAILURE; else return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_send_msg(void *dispr, struct phl_msg *msg, struct phl_msg_attribute *attr, u32 *msg_hdl) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct phl_dispr_msg_ex *msg_ex = NULL; u8 module_id = MSG_MDL_ID_FIELD(msg->msg_id); /* msg src */ u32 req_status = 0; u8 cur_req_id = get_cur_cmd_req_id(obj, &req_status); enum rtw_phl_status sts = RTW_PHL_STATUS_FAILURE; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) { sts = RTW_PHL_STATUS_UNEXPECTED_ERROR; goto err; } if (TEST_STATUS_FLAG(obj->status, DISPR_SHALL_STOP)){ PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_,"%s: dispr shall stop\n", __FUNCTION__); sts = RTW_PHL_STATUS_UNEXPECTED_ERROR; goto err; } if(attr && attr->notify.id_arr == NULL && attr->notify.len) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s attribute err\n",__FUNCTION__); sts = RTW_PHL_STATUS_INVALID_PARAM; goto err; } if (!IS_DISPR_CTRL(module_id) && !_chk_bitmap_bit(obj->bitmap, module_id) && ((cur_req_id != PHL_MDL_ID_MAX && cur_req_id != module_id) || (cur_req_id == PHL_MDL_ID_MAX && req_status == 0)|| (cur_req_id == PHL_MDL_ID_MAX && !TEST_STATUS_FLAG(req_status,REQ_STATUS_LAST_PERMIT)))) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s module not allow to send\n", __FUNCTION__); sts = RTW_PHL_STATUS_INVALID_PARAM; goto err; } if (!pop_front_idle_msg(obj, &msg_ex)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s idle msg empty\n", __FUNCTION__); sts = RTW_PHL_STATUS_RESOURCE; goto err; } if (msg_hdl) *msg_hdl = 0; _os_mem_cpy(d, &msg_ex->msg, msg, sizeof(struct phl_msg)); set_msg_bitmap(obj, msg_ex, module_id); if (attr) { #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ msg_ex->attr = (struct dispr_msg_attr *)attr->dispr_attr; attr->dispr_attr = NULL; #endif set_msg_custom_bitmap(obj, msg_ex, attr->opt, attr->notify.id_arr, attr->notify.len, module_id); if (attr->completion.completion) { SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_NOTIFY_COMPLETE); msg_ex->completion.completion = attr->completion.completion; msg_ex->completion.priv = attr->completion.priv; } if (TEST_STATUS_FLAG(attr->opt, MSG_OPT_CLR_SNDR_MSG_IF_PENDING)) SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_CLR_SNDR_MSG_IF_PENDING); if (TEST_STATUS_FLAG(attr->opt, MSG_OPT_PENDING_DURING_CANNOT_IO)) SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_PENDING_DURING_CANNOT_IO); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, opt:0x%x\n",__FUNCTION__, attr->opt); } if (get_module_by_id(obj, module_id, &(msg_ex->module)) == true) { SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_OWNER_BK_MDL); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s module(%d) found\n", __FUNCTION__, module_id); } else if ((cur_req_id == module_id) || (cur_req_id == PHL_MDL_ID_MAX && TEST_STATUS_FLAG(req_status,REQ_STATUS_LAST_PERMIT))) { SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_OWNER_REQ); } if(TEST_STATUS_FLAG(msg_ex->status, MSG_STATUS_OWNER_REQ) && TEST_STATUS_FLAG(req_status,REQ_STATUS_LAST_PERMIT) && (attr == NULL || !TEST_STATUS_FLAG(attr->opt, MSG_OPT_SEND_IN_ABORT))) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s msg not allow since cur req is going to unload\n", __FUNCTION__); SET_MSG_INDC_FIELD(msg_ex->msg.msg_id, MSG_INDC_FAIL); push_back_idle_msg(obj, msg_ex); sts = RTW_PHL_STATUS_FAILURE; goto exit; } if (TEST_STATUS_FLAG(msg_ex->status, MSG_STATUS_OWNER_REQ) && TEST_STATUS_FLAG(req_status,REQ_STATUS_LAST_PERMIT)) { SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_FOR_ABORT); SET_STATUS_FLAG(obj->status, DISPR_WAIT_ABORT_MSG_DONE); } SET_STATUS_FLAG(msg_ex->status, MSG_STATUS_PRE_PHASE); if (IS_DISPR_CTRL(module_id)) insert_msg_by_priority(obj, msg_ex); else push_back_wait_msg(obj, msg_ex); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, status:0x%x\n",__FUNCTION__, msg_ex->status); if(msg_hdl) *msg_hdl = GEN_VALID_HDL(msg_ex->idx); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, msg_id:0x%x\n", __FUNCTION__, msg->msg_id); return RTW_PHL_STATUS_SUCCESS; err: #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ if(attr) free_dispr_attr(d,(struct dispr_msg_attr **) &(attr->dispr_attr)); #endif exit: return sts; } enum rtw_phl_status dispr_cancel_msg(void *dispr, u32 *msg_hdl) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; struct phl_dispr_msg_ex *msg_ex = NULL; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED) || msg_hdl == NULL) return RTW_PHL_STATUS_UNEXPECTED_ERROR; if (!IS_HDL_VALID(*msg_hdl) || GET_IDX_FROM_HDL(*msg_hdl) >= MAX_PHL_MSG_NUM) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL invalid\n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } msg_ex = &(obj->msg_ex_pool[GET_IDX_FROM_HDL(*msg_hdl)]); *msg_hdl = 0; if (!TEST_STATUS_FLAG(msg_ex->status, MSG_STATUS_ENQ) && !TEST_STATUS_FLAG(msg_ex->status, MSG_STATUS_RUN)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL status err\n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } cancel_msg(obj, msg_ex); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_clr_pending_msg(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; SET_STATUS_FLAG(obj->status, DISPR_CLR_PEND_MSG); notify_bk_thread(obj); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); return RTW_PHL_STATUS_SUCCESS; } enum rtw_phl_status dispr_add_token_req(void *dispr, struct phl_cmd_token_req *req, u32 *req_hdl) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct phl_cmd_token_req_ex *req_ex = NULL; enum rtw_phl_status stat = RTW_PHL_STATUS_SUCCESS; _os_list *node = NULL; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED) || req_hdl == NULL || chk_cmd_req_ops(req) == false) return RTW_PHL_STATUS_UNEXPECTED_ERROR; if (TEST_STATUS_FLAG(obj->status, DISPR_SHALL_STOP)){ PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_,"%s: dispr shall stop\n", __FUNCTION__); return RTW_PHL_STATUS_UNEXPECTED_ERROR; } if (!pop_front_idle_req(obj, &req_ex)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s idle req empty\n", __FUNCTION__); return RTW_PHL_STATUS_RESOURCE; } _os_mem_cpy(d, &(req_ex->req), req, sizeof(struct phl_cmd_token_req)); push_back_wait_req(obj, req_ex); *req_hdl = GEN_VALID_HDL(req_ex->idx); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, id:%d, hdl:0x%x token_cnt:%d\n", __FUNCTION__, req->module_id, *req_hdl, _os_atomic_read(d, &(obj->token_cnt))); if (pq_get_front(d, &(obj->token_op_q), &node, _bh) == false && _os_atomic_read(d, &(obj->token_cnt)) == 0) stat = RTW_PHL_STATUS_SUCCESS; else stat = RTW_PHL_STATUS_PENDING; dispr_enqueue_token_op_info(obj, &req_ex->add_req_info, TOKEN_OP_ADD_CMD_REQ, req_ex->idx); return stat; } enum rtw_phl_status dispr_cancel_token_req(void *dispr, u32 *req_hdl) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; struct phl_cmd_token_req_ex *req_ex = NULL; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED) || req_hdl == NULL) return RTW_PHL_STATUS_UNEXPECTED_ERROR; if (!IS_HDL_VALID(*req_hdl) || GET_IDX_FROM_HDL(*req_hdl) >= MAX_CMD_REQ_NUM) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL(0x%x) invalid\n", __FUNCTION__, *req_hdl); return RTW_PHL_STATUS_FAILURE; } req_ex = &(obj->token_req_ex_pool[GET_IDX_FROM_HDL(*req_hdl)]); if (!TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_ENQ) && !TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_RUN) && !TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_PREPARE)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL(0x%x) status err\n", __FUNCTION__, *req_hdl); return RTW_PHL_STATUS_FAILURE; } if (dispr_enqueue_token_op_info(obj, &req_ex->free_req_info, TOKEN_OP_CANCEL_CMD_REQ, req_ex->idx)) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_free_token(void *dispr, u32 *req_hdl) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct phl_cmd_token_req_ex *req_ex = NULL; if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED) || req_hdl == NULL) return RTW_PHL_STATUS_UNEXPECTED_ERROR; if (obj->cur_cmd_req == NULL || _os_atomic_read(d, &(obj->token_cnt)) == 0 || !IS_HDL_VALID(*req_hdl) || GET_IDX_FROM_HDL(*req_hdl) >= MAX_CMD_REQ_NUM) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL(0x%x) invalid\n", __FUNCTION__, *req_hdl); return RTW_PHL_STATUS_FAILURE; } req_ex = &(obj->token_req_ex_pool[GET_IDX_FROM_HDL(*req_hdl)]); if (!TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_RUN) && !TEST_STATUS_FLAG(req_ex->status, REQ_STATUS_PREPARE)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_ERR_, "%s, HDL(0x%x) mismatch\n", __FUNCTION__, *req_hdl); return RTW_PHL_STATUS_FAILURE; } SET_STATUS_FLAG(req_ex->status, REQ_STATUS_CANCEL); if (dispr_enqueue_token_op_info(obj, &req_ex->free_req_info, TOKEN_OP_FREE_CMD_REQ, req_ex->idx)) return RTW_PHL_STATUS_SUCCESS; else return RTW_PHL_STATUS_FAILURE; } enum rtw_phl_status dispr_notify_dev_io_status(void *dispr, enum phl_module_id mdl_id, bool allow_io) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS; if (allow_io == false) { if (!TEST_STATUS_FLAG(obj->status, DISPR_CANNOT_IO)) { SET_STATUS_FLAG(obj->status, DISPR_CANNOT_IO); SET_EXCL_MDL(obj, mdl_id); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, mdl_id(%d) notify cannot io\n", __FUNCTION__, mdl_id); status = send_dev_io_status_change(obj, allow_io); } } else { if (TEST_STATUS_FLAG(obj->status, DISPR_CANNOT_IO)) { CLEAR_STATUS_FLAG(obj->status, DISPR_CANNOT_IO); CLEAR_EXCL_MDL(obj); status = send_dev_io_status_change(obj, allow_io); dispr_clr_pending_msg(dispr); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, mdl_id(%d) notify io resume\n", __FUNCTION__, mdl_id); } } return status; } void dispr_notify_shall_stop(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; if (!TEST_STATUS_FLAG(obj->status, DISPR_SHALL_STOP)) { SET_STATUS_FLAG(obj->status, DISPR_SHALL_STOP); dispr_clr_pending_msg(dispr); PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, notify shall stop\n", __FUNCTION__); } } u8 dispr_is_fg_empty(void *dispr) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; bool is_empty = true; void *drv = phl_to_drvpriv(obj->phl_info); struct phl_queue *q = NULL; _os_list *node = NULL; do { /* shall check wait queue first then check token op queue * to avoid to get the incorrect empty state of fg cmd */ q = &(obj->token_req_wait_q); _os_spinlock(drv, &(q->lock), _bh, NULL); if(!list_empty(&q->queue) && (q->cnt > 0)) { is_empty = false; _os_spinunlock(drv, &(q->lock), _bh, NULL); break; } _os_spinunlock(drv, &(q->lock), _bh, NULL); if (pq_get_front(drv, &(obj->token_op_q), &node, _bh) == true || _os_atomic_read(drv, &(obj->token_cnt)) > 0) { is_empty = false; break; } } while(false); return is_empty; } enum rtw_phl_status dispr_process_token_req(struct cmd_dispatcher *obj) { void *d = phl_to_drvpriv(obj->phl_info); struct phl_cmd_token_req_ex *ex = NULL; do { if (!TEST_STATUS_FLAG(obj->status, DISPR_STARTED)) return RTW_PHL_STATUS_UNEXPECTED_ERROR; if (TEST_STATUS_FLAG(obj->status, DISPR_SHALL_STOP)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s: dispr shall stop\n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } if (_os_atomic_read(d, &(obj->token_cnt)) > 0) return RTW_PHL_STATUS_FAILURE; if (TEST_STATUS_FLAG(obj->status, DISPR_WAIT_ABORT_MSG_DONE)) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s, wait for abort msg sent from prev req finish before register next req \n", __FUNCTION__); return RTW_PHL_STATUS_FAILURE; } if (pop_front_wait_req(obj, &ex) == false) { if (!TEST_STATUS_FLAG(obj->status, DISPR_NOTIFY_IDLE)) { SET_STATUS_FLAG(obj->status, DISPR_NOTIFY_IDLE); send_bk_msg_phy_idle(obj); } return RTW_PHL_STATUS_SUCCESS; } if (TEST_STATUS_FLAG(obj->status, DISPR_NOTIFY_IDLE)) { CLEAR_STATUS_FLAG(obj->status, DISPR_NOTIFY_IDLE); send_bk_msg_phy_on(obj); } }while(!register_cur_cmd_req(obj, ex)); return RTW_PHL_STATUS_SUCCESS; } void dispr_share_thread_loop_hdl(void *dispr) { dispr_thread_loop_hdl( (struct cmd_dispatcher *)dispr); } void dispr_share_thread_leave_hdl(void *dispr) { dispr_thread_leave_hdl((struct cmd_dispatcher *)dispr); } void dispr_share_thread_stop_prior_hdl(void *dispr) { dispr_thread_stop_prior_hdl((struct cmd_dispatcher *)dispr); } void dispr_share_thread_stop_post_hdl(void *dispr) { dispr_thread_stop_post_hdl((struct cmd_dispatcher *)dispr); } u8 disp_query_mdl_id(struct phl_info_t *phl, void *bk_mdl) { struct phl_bk_module *mdl = NULL; if (bk_mdl != NULL) { mdl = (struct phl_bk_module *)bk_mdl; return mdl->id; } else { return PHL_MDL_ID_MAX; } } void send_bk_msg_phy_on(struct cmd_dispatcher *obj) { struct phl_msg msg = {0}; struct phl_msg_attribute attr = {0}; SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT); SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_PHY_ON); dispr_send_msg((void*)obj, &msg, &attr, NULL); } void send_bk_msg_phy_idle(struct cmd_dispatcher *obj) { struct phl_msg msg = {0}; struct phl_msg_attribute attr = {0}; SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_POWER_MGNT); SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_PHY_IDLE); dispr_send_msg((void*)obj, &msg, &attr, NULL); } enum rtw_phl_status send_dev_io_status_change(struct cmd_dispatcher *obj, u8 allow_io) { struct phl_msg msg = {0}; struct phl_msg_attribute attr = {0}; u16 event = (allow_io == true) ? (MSG_EVT_DEV_RESUME_IO) : (MSG_EVT_DEV_CANNOT_IO); SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_PHY_MGNT); SET_MSG_EVT_ID_FIELD(msg.msg_id, event); return dispr_send_msg((void*)obj, &msg, &attr, NULL); } #ifdef CONFIG_CMD_DISP_SUPPORT_CUSTOM_SEQ enum phl_mdl_ret_code loop_through_map(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, enum phl_bk_module_priority priority, struct msg_notify_map *map, u8 pre_prot_phase) { u8 i = 0; struct phl_bk_module *mdl = NULL; enum phl_mdl_ret_code ret = MDL_RET_IGNORE; u8 *bitmap = (pre_prot_phase == true) ? (ex->premap) : (ex->postmap); for (i = 0 ; i < map->len; i++) { if (map->id_arr[i] >= PHL_FG_MDL_START) { PHL_TRACE(COMP_PHL_CMDDISP, _PHL_WARNING_, "%s, cmd req does not take precedence over bk module\n", __FUNCTION__); continue; } mdl = (struct phl_bk_module *)GET_MDL_HANDLE(obj, map->id_arr[i]); if (mdl == NULL || !_chk_bitmap_bit(bitmap, mdl->id)) continue; /*only allow sequence rearrange for modules at the same priority*/ if ( _get_mdl_priority(mdl->id) != priority) continue; ret = feed_mdl_msg(obj, mdl, ex); if (STOP_DISPATCH_MSG(ret)) return ret; } return ret; } static enum phl_mdl_ret_code run_self_def_seq(struct cmd_dispatcher *obj, struct phl_dispr_msg_ex *ex, enum phl_bk_module_priority priority, u8 pre_prot_phase) { struct msg_notify_map *map = NULL; enum phl_mdl_ret_code ret = MDL_RET_IGNORE; struct msg_dispatch_seq* seq = NULL; if (ex->attr == NULL) return ret; /*MANDATORY modules cannot change dispatch order*/ if (pre_prot_phase == true) seq = &(ex->attr->self_def_seq.pre_prot_phase); else seq = &(ex->attr->self_def_seq.post_prot_phase); return loop_through_map(obj, ex, priority, &(seq->map[priority]), pre_prot_phase); } void reset_self_def_seq(void *d, struct msg_self_def_seq* self_def_seq) { u8 i = 0; u8 cnt = 0; struct msg_dispatch_seq *seq = (struct msg_dispatch_seq *)self_def_seq; while (cnt++ < 2) { for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if (seq->map[i].len) _os_kmem_free(d, seq->map[i].id_arr, seq->map[i].len); seq->map[i].id_arr = NULL; seq->map[i].len = 0; } seq++; } } u8 copy_self_def_seq(void *d, struct msg_self_def_seq* self_def_dest, struct msg_self_def_seq* self_def_src) { u8 i = 0; u8 cnt = 0; struct msg_dispatch_seq *dest = (struct msg_dispatch_seq *)self_def_dest; struct msg_dispatch_seq *src = (struct msg_dispatch_seq *)self_def_src; while (cnt++ < 2) { for (i = 0; i < PHL_MDL_PRI_MAX; i++) { if (src->map[i].len) { dest->map[i].id_arr = _os_kmem_alloc(d, src->map[i].len); if (dest->map[i].id_arr == NULL) return false; dest->map[i].len = src->map[i].len; _os_mem_cpy(d, dest->map[i].id_arr, src->map[i].id_arr, dest->map[i].len); } } dest++; src++; } return true; } inline static u8 alloc_dispr_attr(void *d, struct phl_msg_attribute *attr) { if (attr->dispr_attr == NULL) attr->dispr_attr = _os_kmem_alloc(d, sizeof(struct dispr_msg_attr)); if (attr->dispr_attr != NULL) _os_mem_set(d, attr->dispr_attr, sizeof(struct dispr_msg_attr)); return (attr->dispr_attr == NULL) ? (false) : (true); } enum rtw_phl_status dispr_set_dispatch_seq(void *dispr, struct phl_msg_attribute *attr, struct msg_self_def_seq* seq) { struct cmd_dispatcher *obj = (struct cmd_dispatcher *)dispr; void *d = phl_to_drvpriv(obj->phl_info); struct dispr_msg_attr *dispr_attr = NULL; if (attr == NULL || seq == NULL) return RTW_PHL_STATUS_INVALID_PARAM; if (alloc_dispr_attr(d, attr) == false) goto err_attr_alloc; dispr_attr = attr->dispr_attr; reset_self_def_seq(d, &(dispr_attr->self_def_seq)); if (copy_self_def_seq(d, &(dispr_attr->self_def_seq), seq) == false) goto err_seq_copy; return RTW_PHL_STATUS_SUCCESS; err_seq_copy: free_dispr_attr(d, &(attr->dispr_attr)); err_attr_alloc: PHL_TRACE(COMP_PHL_CMDDISP, _PHL_WARNING_, "%s, err\n", __FUNCTION__); return RTW_PHL_STATUS_RESOURCE; } static void free_dispr_attr(void *d, struct dispr_msg_attr **dispr_attr) { struct dispr_msg_attr *attr = NULL; if (dispr_attr == NULL || *dispr_attr == NULL) return; PHL_TRACE(COMP_PHL_CMDDISP, _PHL_INFO_, "%s\n", __FUNCTION__); attr = *dispr_attr; reset_self_def_seq(d, &(attr->self_def_seq)); _os_kmem_free(d, attr, sizeof(struct dispr_msg_attr)); *dispr_attr = NULL; } #endif #endif