驱动层WALN 状态机运行机制
wlan_sm 状态机基类介绍
状态机基本struct信息
状态机信息结构体:
struct wlan_sm_state_infostruct wlan_sm_state_info { uint8_t state; // 当前状态 uint8_t parent_state; // 父状态 uint8_t initial_substate; // 子状态 uint8_t has_substates; // 是否有子状态标志 const char *name; // 状态的名字 void (*wlan_sm_entry) (void *ctx);// entry回调 void (*wlan_sm_exit) (void *ctx);// exit回调 bool (*wlan_sm_event) (void *ctx, uint16_t event,uint16_t event_data_len, void *event_data);/// 事件回调 };
比如我们定义一个状态机的时候,首先定义各个状态对应的
struct wlan_sm_state_info,如下:struct wlan_sm_state_info sm_info[] = { { (uint8_t)WLAN_VDEV_S_INIT, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "INIT", mlme_vdev_state_init_entry, mlme_vdev_state_init_exit, mlme_vdev_state_init_event }, { (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "START", mlme_vdev_state_start_entry, mlme_vdev_state_start_exit, mlme_vdev_state_start_event } };
状态机事件名字
事件名字代表事件的字符串表达
static const char *vdev_sm_event_names[] = { "EV_START", "EV_START_REQ", "EV_RESTART_REQ", };
状态机结构体:
struct wlan_smstruct wlan_sm { uint8_t name[WLAN_SM_ENGINE_MAX_NAME]; // 该状态机的名字 uint8_t cur_state;// 当前状态 uint8_t num_states;// 该状态机一共有多少个状态 uint8_t last_event;// 上次事件 struct wlan_sm_state_info *state_info;// 该状态机的 状态信息,里面存放着每个状态的 回调函数 具体参见 struct wlan_sm_state_info void *ctx;// 用户指针 qdf_atomic_t in_state_transition;// 锁 const char **event_names;// 该状态机所拥有的所有事件名字数组 就是上面第2部提到的 static const char *vdev_sm_event_names[] uint32_t num_event_names;// 一共多少个事件,取决于 static const char *vdev_sm_event_names[] 数组的大小 #ifdef SM_ENG_HIST_ENABLE struct wlan_sm_history history;// 用来记录状态机变迁的历史记录 #endif };
状态机api函数
创建状态机函数
/** * wlan_sm_create() - SM create * @name: 该状态机名字 * @ctx: caller pointer:用户指针 * @init_state: 默认初始化状态 * @state_info:状态机信息。里面存放各个状态对应的回调函数 * @num_state: 该状态机一共有多少个状态 * @event_names:事件表对应的名字 * @num_event_names: 一共有多少个事件 * * 创建状态机 * * Return: struct wlan_sm 句柄 * NULL 创建失败 */ struct wlan_sm *wlan_sm_create(const char *name, void *ctx, uint8_t init_state, struct wlan_sm_state_info *state_info, uint8_t num_states, const char **event_names, uint32_t num_event_names); { struct wlan_sm *sm; u_int32_t i; // 创建内存 sm = qdf_mem_malloc(sizeof(*sm)); // 保存历史相关 wlan_sm_history_init(sm); // 把 传入参数传入 到sm 结构体中 sm->cur_state = init_state; sm->num_states = num_states; sm->state_info = state_info; sm->ctx = ctx; sm->last_event = WLAN_SM_ENGINE_EVENT_NONE; qdf_atomic_set(&sm->in_state_transition, 0); // 初始化锁 sm->event_names = event_names; sm->num_event_names = num_event_names; qdf_str_lcopy(sm->name, name, WLAN_SM_ENGINE_MAX_NAME); return sm; }
删除状态机
void wlan_sm_delete(struct wlan_sm *sm) { wlan_sm_history_delete(sm); // 删除历史相关 qdf_mem_free(sm); // 直接释放sm内存 }
状态机事件dispatch
/** * wlan_sm_dispatch() - API to notify event to SM * @sm: 状态机句柄 * @event: 事件id * @event_data_len: 事件数据长度 * @event_data: 事件数据 * * 通知事件到 状态机sm,并回调对应状态下的函数 * * Return: QDF_STATUS_SUCCESS 处理成功 * QDF_STATUS_E_INVAL 处理失败 */ QDF_STATUS wlan_sm_dispatch(struct wlan_sm *sm, uint16_t event, uint16_t event_data_len, void *event_data) { bool event_handled = false; uint8_t state; const char *event_name = NULL; state = sm->cur_state; // 记录 上此发生的事件 sm->last_event = event; // 记录历史 wlan_sm_save_history(sm, SM_EVENT_MSG_PROCESSING, sm->cur_state,sm->cur_state, event); // 如果当前状态不为空,找到 该状态下event 处理函数 wlan_sm_event,进行 回调 这里 并没有 进行转态变迁,只是做了wlan_sm_event的回调 if (state != WLAN_SM_ENGINE_STATE_NONE) { // 回调当前状态下的 wlan_sm_event 函数 event_handled = (*sm->state_info[state].wlan_sm_event) (sm->ctx, event, event_data_len, event_data); if (!event_handled) { sm_engine_nofl_info("%s: event %d not handled in state %s", sm->name, event, sm->state_info[sm->cur_state].name); return QDF_STATUS_E_INVAL; } } return QDF_STATUS_SUCCESS; }
从上面的分析可以看出
该函数记录上次发生了什么事件
sm->last_event = event;该函数只调用了事件的处理函数
wlan_sm_event,并没有进行任何状态的变迁, 当然在wlan_sm_event函数中 有可能进行状态变迁
状态机传输函数,变迁状态到新的状态
/** * wlan_sm_transition_to() - API to move the state of SM * @sm: 状态机处理句柄 * @state: 将要变迁到的状态 */ void wlan_sm_transition_to(struct wlan_sm *sm, uint8_t state) { struct wlan_sm_state_info *state_info; uint8_t new_state; uint8_t old_state; uint8_t new_sub_st; uint8_t ol_sub_st; uint8_t cur_state; state_info = sm->state_info; cur_state = sm->cur_state; /* * cannot change state from state entry/exit routines * 不能够在状态enrty或者exit中 执行 转态变迁,锁子呢在 */ if (qdf_atomic_read(&sm->in_state_transition)) { sm_engine_alert( "%s: can not call state transition from entry/exit routines", sm->name); QDF_BUG(0); return; } // 上锁 qdf_atomic_set(&sm->in_state_transition, 1); // 保存历史 wlan_sm_save_history(sm, SM_EVENT_STATE_TRANSITION, sm->cur_state,state, 0xFF); // 新状态合法性检查 if ((state == WLAN_SM_ENGINE_STATE_NONE) || (state >= WLAN_SM_ENGINE_MAX_STATES) || (state >= sm->num_states)) { sm_engine_err( "%s: to state %d needs to be a valid state current_state=%d", sm->name, cur_state, state); return; } /* * Here state and sub state are derived for debug printing only * as SME keeps state and sub state as flat, to differentiate between * state and substate, checks current state if it has parent state, * the parent state is printed along with the sub state */ // 下面这一堆 没什么用,只是用来打印, // 思想就是 /* *old_state ol_sub_st * state_info[cur_state].parent_state; cur_state 情况1 当前状态有 父状态 * cur_state 0 情况2 当前状态没有 父状态 */ /* * new_state new_sub_st * state_info[state].parent_state; state 情况1 将要变迁状态 有 父状态 * state 0 情况2 将要变迁状态 没有 父状态 */ if (state_info[cur_state].parent_state != WLAN_SM_ENGINE_STATE_NONE) old_state = state_info[cur_state].parent_state; else old_state = cur_state; if (state_info[state].parent_state != WLAN_SM_ENGINE_STATE_NONE) new_state = state_info[state].parent_state; else new_state = state; if (state_info[cur_state].parent_state != WLAN_SM_ENGINE_STATE_NONE) ol_sub_st = cur_state; else ol_sub_st = 0; if (state_info[state].parent_state != WLAN_SM_ENGINE_STATE_NONE) new_sub_st = state; else new_sub_st = 0; sm_engine_nofl_debug("%s: %s > %s, %s > %s", sm->name, state_info[old_state].name, state_info[new_state].name, ol_sub_st ? state_info[ol_sub_st].name : "IDLE", new_sub_st ? state_info[new_sub_st].name : "IDLE"); /* * 要从 cur_state 变迁到 新的状态 state * 调用 cur_state 下的 退出函数 wlan_sm_exit * 如果 cur_state 有父状态,顺序 调用 他的父状态 的退出函数 */ while (cur_state != WLAN_SM_ENGINE_STATE_NONE) { if (state_info[cur_state].wlan_sm_exit) state_info[cur_state].wlan_sm_exit(sm->ctx); cur_state = state_info[cur_state].parent_state; } /* * 要从 cur_state 变迁到 新的状态 state * 调用 state 下的 进入函数 wlan_sm_entry * 如果 state 有子状态,顺序 调用 他的子状态 的进入函数 * 并且 把状态机的sm->cur_state 更新为最后一次调用的 状态,如果最后一次是子状态,就赋值为子状态, */ cur_state = state; while (cur_state != WLAN_SM_ENGINE_STATE_NONE) { if (state_info[cur_state].wlan_sm_entry) state_info[cur_state].wlan_sm_entry(sm->ctx); sm->cur_state = cur_state; cur_state = state_info[cur_state].initial_substate; if (cur_state != WLAN_SM_ENGINE_STATE_NONE) sm_engine_nofl_debug("%s: Initial sub state %s", sm->name, state_info[cur_state].name); } // 解锁 qdf_atomic_set(&sm->in_state_transition, 0); }
从上面的分析可以看出:
该函数先调用当前状态sm->cur_state的退出函数,如果有父状态,顺序调用它父亲的退出函数;
调用要变迁的状态state 的进入函数,如果有子状态,也调用它的子状态的进入函数,并且把 状态机的 当前状态 变迁到 state(ps:如果有子状态就是 子状态)
得到上次的事件
uint8_t wlan_sm_get_lastevent(struct wlan_sm *sm) { return sm->last_event; }
得到当前状态
uint8_t wlan_sm_get_current_state(struct wlan_sm *sm) { return sm->cur_state; }
得到状态的名字
const char *wlan_sm_get_state_name(struct wlan_sm *sm, uint8_t state) { return sm->state_info[state].name; }
得到当前状态的名字
const char *wlan_sm_get_current_state_name(struct wlan_sm *sm) { return sm->state_info[sm->cur_state].name; }
wlan_sm 状态机示例mlme状态机
创建状态机
QDF_STATUS mlme_vdev_sm_create(struct vdev_mlme_obj *vdev_mlme) { struct wlan_sm *sm; uint8_t name[WLAN_SM_ENGINE_MAX_NAME]; struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; qdf_scnprintf(name, sizeof(name), "VDEV%d-MLME",wlan_vdev_get_id(vdev_mlme->vdev)); // 创建状态机, // 状态机名字为 VDEV%d-MLME // 初始化状态为 WLAN_VDEV_S_INIT // 状态信息表为 sm_info // 状态机事件名字为 vdev_sm_event_names sm = wlan_sm_create(name, vdev_mlme, WLAN_VDEV_S_INIT, sm_info, QDF_ARRAY_SIZE(sm_info), vdev_sm_event_names, QDF_ARRAY_SIZE(vdev_sm_event_names)); vdev_mlme->sm_hdl = sm; return QDF_STATUS_SUCCESS; }
上面函数提到的mlme状态机的:
状态信息表:
struct wlan_sm_state_info sm_info[] = { { (uint8_t)WLAN_VDEV_S_INIT, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "INIT", mlme_vdev_state_init_entry, mlme_vdev_state_init_exit, mlme_vdev_state_init_event }, { (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "START", mlme_vdev_state_start_entry, mlme_vdev_state_start_exit, mlme_vdev_state_start_event }, { (uint8_t)WLAN_VDEV_S_DFS_CAC_WAIT, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "DFS_CAC_WAIT", mlme_vdev_state_dfs_cac_wait_entry, mlme_vdev_state_dfs_cac_wait_exit, mlme_vdev_state_dfs_cac_wait_event }, { (uint8_t)WLAN_VDEV_S_UP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "UP", mlme_vdev_state_up_entry, mlme_vdev_state_up_exit, mlme_vdev_state_up_event }, { (uint8_t)WLAN_VDEV_S_SUSPEND, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, true, "SUSPEND", mlme_vdev_state_suspend_entry, mlme_vdev_state_suspend_exit, mlme_vdev_state_suspend_event }, { (uint8_t)WLAN_VDEV_S_STOP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_VDEV_SS_STOP_STOP_PROGRESS, true, "STOP", mlme_vdev_state_stop_entry, mlme_vdev_state_stop_exit, mlme_vdev_state_stop_event }, { (uint8_t)WLAN_VDEV_S_MAX, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "INVALID", NULL, NULL, NULL }, { (uint8_t)WLAN_VDEV_SS_START_START_PROGRESS, (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "ST-START_PROG", mlme_vdev_subst_start_start_progress_entry, mlme_vdev_subst_start_start_progress_exit, mlme_vdev_subst_start_start_progress_event }, { (uint8_t)WLAN_VDEV_SS_START_RESTART_PROGRESS, (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "ST-RESTART_PROG", mlme_vdev_subst_start_restart_progress_entry, mlme_vdev_subst_start_restart_progress_exit, mlme_vdev_subst_start_restart_progress_event }, { (uint8_t)WLAN_VDEV_SS_START_CONN_PROGRESS, (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "ST-CONN_PROG", mlme_vdev_subst_start_conn_progress_entry, mlme_vdev_subst_start_conn_progress_exit, mlme_vdev_subst_start_conn_progress_event }, { (uint8_t)WLAN_VDEV_SS_START_DISCONN_PROGRESS, (uint8_t)WLAN_VDEV_S_START, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "ST-DISCONN_PROG", mlme_vdev_subst_start_disconn_progress_entry, mlme_vdev_subst_start_disconn_progress_exit, mlme_vdev_subst_start_disconn_progress_event }, { (uint8_t)WLAN_VDEV_SS_SUSPEND_SUSPEND_DOWN, (uint8_t)WLAN_VDEV_S_SUSPEND, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "SP-SUSPEND_DOWN", mlme_vdev_subst_suspend_suspend_down_entry, mlme_vdev_subst_suspend_suspend_down_exit, mlme_vdev_subst_suspend_suspend_down_event }, { (uint8_t)WLAN_VDEV_SS_SUSPEND_SUSPEND_RESTART, (uint8_t)WLAN_VDEV_S_SUSPEND, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "SP-SUSPEND_RESTART", mlme_vdev_subst_suspend_suspend_restart_entry, mlme_vdev_subst_suspend_suspend_restart_exit, mlme_vdev_subst_suspend_suspend_restart_event }, { (uint8_t)WLAN_VDEV_SS_SUSPEND_HOST_RESTART, (uint8_t)WLAN_VDEV_S_SUSPEND, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "SP-HOST_RESTART", mlme_vdev_subst_suspend_host_restart_entry, mlme_vdev_subst_suspend_host_restart_exit, mlme_vdev_subst_suspend_host_restart_event }, { (uint8_t)WLAN_VDEV_SS_SUSPEND_CSA_RESTART, (uint8_t)WLAN_VDEV_S_SUSPEND, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "SP-CSA_RESTART", mlme_vdev_subst_suspend_csa_restart_entry, mlme_vdev_subst_suspend_csa_restart_exit, mlme_vdev_subst_suspend_csa_restart_event }, { (uint8_t)WLAN_VDEV_SS_STOP_STOP_PROGRESS, (uint8_t)WLAN_VDEV_S_STOP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "STOP-STOP_PROG", mlme_vdev_subst_stop_stop_progress_entry, mlme_vdev_subst_stop_stop_progress_exit, mlme_vdev_subst_stop_stop_progress_event }, { (uint8_t)WLAN_VDEV_SS_STOP_DOWN_PROGRESS, (uint8_t)WLAN_VDEV_S_STOP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "STOP-DOWN_PROG", mlme_vdev_subst_stop_down_progress_entry, mlme_vdev_subst_stop_down_progress_exit, mlme_vdev_subst_stop_down_progress_event }, { (uint8_t)WLAN_VDEV_SS_IDLE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "IDLE", NULL, NULL, NULL, }, { (uint8_t)WLAN_VDEV_SS_MLO_SYNC_WAIT, (uint8_t)WLAN_VDEV_S_UP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "UP-MLO-SYNC-WAIT", mlme_vdev_subst_mlo_sync_wait_entry, mlme_vdev_subst_mlo_sync_wait_exit, mlme_vdev_subst_mlo_sync_wait_event }, { (uint8_t)WLAN_VDEV_SS_UP_ACTIVE, (uint8_t)WLAN_VDEV_S_UP, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "UP-UP-ACTIVE", mlme_vdev_subst_up_active_entry, mlme_vdev_subst_up_active_exit, mlme_vdev_subst_up_active_event }, { (uint8_t)WLAN_VDEV_SS_MAX, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, (uint8_t)WLAN_SM_ENGINE_STATE_NONE, false, "INVALID", NULL, NULL, NULL, }, };
事件名字
static const char *vdev_sm_event_names[] = { "EV_START", "EV_START_REQ", "EV_RESTART_REQ", "EV_START_RESP", "EV_RESTART_RESP", "EV_START_REQ_FAIL", "EV_RESTART_REQ_FAIL", "EV_START_SUCCESS", "EV_CONN_PROGRESS", "EV_STA_CONN_START", "EV_DFS_CAC_WAIT", "EV_DFS_CAC_COMPLETED", "EV_DOWN", "EV_CONNECTION_FAIL", "EV_STOP_RESP", "EV_STOP_FAIL", "EV_DOWN_FAIL", "EV_DISCONNECT_COMPLETE", "EV_SUSPEND_RESTART", "EV_HOST_RESTART", "EV_UP_HOST_RESTART", "EV_FW_VDEV_RESTART", "EV_UP_FAIL", "EV_RADAR_DETECTED", "EV_CSA_RESTART", "EV_CSA_COMPLETE", "EV_MLME_DOWN_REQ", "EV_DOWN_COMPLETE", "EV_ROAM", "EV_STOP_REQ", "EV_CHAN_SWITCH_DISABLED", "EV_MLO_SYNC_COMPLETE", };
所有状态
/** * enum wlan_vdev_state - VDEV state * @WLAN_VDEV_S_INIT: Default state, IDLE state * @WLAN_VDEV_S_START: START state * @WLAN_VDEV_S_DFS_CAC_WAIT: CAC period * @WLAN_VDEV_S_UP: UP state * @WLAN_VDEV_S_SUSPEND: Suspend state * @WLAN_VDEV_S_STOP: STOP state * @WLAN_VDEV_S_MAX: MAX state * @WLAN_VDEV_SS_START_START_PROGRESS: Start progress sub state * @WLAN_VDEV_SS_START_RESTART_PROGRESS: Restart progress sub state * @WLAN_VDEV_SS_START_CONN_PROGRESS: Start connection progress sub state * @WLAN_VDEV_SS_START_DISCONN_PROGRESS: Start Disconnection progress sub state * @WLAN_VDEV_SS_SUSPEND_SUSPEND_DOWN: Suspend down sub state * @WLAN_VDEV_SS_SUSPEND_SUSPEND_RESTART: Suspend restart sub state * @WLAN_VDEV_SS_SUSPEND_HOST_RESTART: Suspend host restart sub state * @WLAN_VDEV_SS_SUSPEND_CSA_RESTART: Suspend CSA restart sub state * @WLAN_VDEV_SS_STOP_STOP_PROGRESS: Stop progress sub state * @WLAN_VDEV_SS_STOP_DOWN_PROGRESS: Stop down progress sub state * @WLAN_VDEV_SS_IDLE: Idle sub state (used, only if a state * does not have substate) * @WLAN_VDEV_SS_MLO_SYNC_WAIT: Sync wait sub state for MLO SAP * @WLAN_VDEV_SS_UP_ACTIVE: Up active sub state * @WLAN_VDEV_SS_MAX: Max substate */ enum wlan_vdev_state { WLAN_VDEV_S_INIT = 0, WLAN_VDEV_S_START = 1, WLAN_VDEV_S_DFS_CAC_WAIT = 2, WLAN_VDEV_S_UP = 3, WLAN_VDEV_S_SUSPEND = 4, WLAN_VDEV_S_STOP = 5, WLAN_VDEV_S_MAX = 6, WLAN_VDEV_SS_START_START_PROGRESS = 7, WLAN_VDEV_SS_START_RESTART_PROGRESS = 8, WLAN_VDEV_SS_START_CONN_PROGRESS = 9, WLAN_VDEV_SS_START_DISCONN_PROGRESS = 10, WLAN_VDEV_SS_SUSPEND_SUSPEND_DOWN = 11, WLAN_VDEV_SS_SUSPEND_SUSPEND_RESTART = 12, WLAN_VDEV_SS_SUSPEND_HOST_RESTART = 13, WLAN_VDEV_SS_SUSPEND_CSA_RESTART = 14, WLAN_VDEV_SS_STOP_STOP_PROGRESS = 15, WLAN_VDEV_SS_STOP_DOWN_PROGRESS = 16, WLAN_VDEV_SS_IDLE = 17, WLAN_VDEV_SS_MLO_SYNC_WAIT = 18, WLAN_VDEV_SS_UP_ACTIVE = 19, WLAN_VDEV_SS_MAX = 20, };
所有事件
/** * enum wlan_vdev_sm_evt - VDEV SM event * @WLAN_VDEV_SM_EV_START: Start VDEV UP operation * @WLAN_VDEV_SM_EV_START_REQ: Invokes VDEV START handshake * @WLAN_VDEV_SM_EV_RESTART_REQ: Invokes VDEV RESTART handshake * @WLAN_VDEV_SM_EV_START_RESP: Notification on START resp * @WLAN_VDEV_SM_EV_RESTART_RESP: Notification on RESTART resp * @WLAN_VDEV_SM_EV_START_REQ_FAIL: Notification on START req failure * @WLAN_VDEV_SM_EV_RESTART_REQ_FAIL: Notification on RESTART req failure * @WLAN_VDEV_SM_EV_START_SUCCESS: Notification of Join Success * @WLAN_VDEV_SM_EV_CONN_PROGRESS: Invoke Connection/up process * @WLAN_VDEV_SM_EV_STA_CONN_START: Invoke Station Connection process * @WLAN_VDEV_SM_EV_DFS_CAC_WAIT: Invoke DFS CAC WAIT timer * @WLAN_VDEV_SM_EV_DFS_CAC_COMPLETED: Notifies on CAC completion * @WLAN_VDEV_SM_EV_DOWN: Invokes VDEV DOWN operation * @WLAN_VDEV_SM_EV_CONNECTION_FAIL: Notifications for UP/connection failure * @WLAN_VDEV_SM_EV_STOP_RESP: Notifcation of stop response * @WLAN_VDEV_SM_EV_STOP_FAIL: Notification of stop req failure * @WLAN_VDEV_SM_EV_DOWN_FAIL: Notification of down failure * @WLAN_VDEV_SM_EV_DISCONNECT_COMPLETE: Notification of Peer cleanup complete * @WLAN_VDEV_SM_EV_SUSPEND_RESTART: Invokes suspend restart operation * @WLAN_VDEV_SM_EV_HOST_RESTART: Invokes host only restart operation * @WLAN_VDEV_SM_EV_UP_HOST_RESTART: Moves to UP state without sending UP * command to lower layers * @WLAN_VDEV_SM_EV_FW_VDEV_RESTART: Invokes FW only restart * @WLAN_VDEV_SM_EV_UP_FAIL: Notification of up command failure * @WLAN_VDEV_SM_EV_RADAR_DETECTED: Notification of RADAR detected, Random * channel should be selected before * triggering this event * @WLAN_VDEV_SM_EV_CSA_RESTART: Invokes CSA IE operation * @WLAN_VDEV_SM_EV_CSA_COMPLETE: Notifiction of CSA process complete * @WLAN_VDEV_SM_EV_MLME_DOWN_REQ: Invoke DOWN command operation * @WLAN_VDEV_SM_EV_DOWN_COMPLETE: Notification of DOWN complete * @WLAN_VDEV_SM_EV_ROAM: Notifiction on ROAMING * @WLAN_VDEV_SM_EV_STOP_REQ: Invoke API to initiate STOP handshake * @WLAN_VDEV_SM_EV_CHAN_SWITCH_DISABLED:Test only, CSA completes without * change in channel * @WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE: MLO mgr triggers this event for the mlo * sap in vdev wait up state, if all the * links finish vdev start rsp. */ enum wlan_vdev_sm_evt { WLAN_VDEV_SM_EV_START = 0, WLAN_VDEV_SM_EV_START_REQ = 1, WLAN_VDEV_SM_EV_RESTART_REQ = 2, WLAN_VDEV_SM_EV_START_RESP = 3, WLAN_VDEV_SM_EV_RESTART_RESP = 4, WLAN_VDEV_SM_EV_START_REQ_FAIL = 5, WLAN_VDEV_SM_EV_RESTART_REQ_FAIL = 6, WLAN_VDEV_SM_EV_START_SUCCESS = 7, WLAN_VDEV_SM_EV_CONN_PROGRESS = 8, WLAN_VDEV_SM_EV_STA_CONN_START = 9, WLAN_VDEV_SM_EV_DFS_CAC_WAIT = 10, WLAN_VDEV_SM_EV_DFS_CAC_COMPLETED = 11, WLAN_VDEV_SM_EV_DOWN = 12, WLAN_VDEV_SM_EV_CONNECTION_FAIL = 13, WLAN_VDEV_SM_EV_STOP_RESP = 14, WLAN_VDEV_SM_EV_STOP_FAIL = 15, WLAN_VDEV_SM_EV_DOWN_FAIL = 16, WLAN_VDEV_SM_EV_DISCONNECT_COMPLETE = 17, WLAN_VDEV_SM_EV_SUSPEND_RESTART = 18, WLAN_VDEV_SM_EV_HOST_RESTART = 19, WLAN_VDEV_SM_EV_UP_HOST_RESTART = 20, WLAN_VDEV_SM_EV_FW_VDEV_RESTART = 21, WLAN_VDEV_SM_EV_UP_FAIL = 22, WLAN_VDEV_SM_EV_RADAR_DETECTED = 23, WLAN_VDEV_SM_EV_CSA_RESTART = 24, WLAN_VDEV_SM_EV_CSA_COMPLETE = 25, WLAN_VDEV_SM_EV_MLME_DOWN_REQ = 26, WLAN_VDEV_SM_EV_DOWN_COMPLETE = 27, WLAN_VDEV_SM_EV_ROAM = 28, WLAN_VDEV_SM_EV_STOP_REQ = 29, WLAN_VDEV_SM_EV_CHAN_SWITCH_DISABLED = 30, WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE = 31, };
事件通知
QDF_STATUS mlme_vdev_sm_deliver_event(struct vdev_mlme_obj *vdev_mlme, enum wlan_vdev_sm_evt event, uint16_t event_data_len, void *event_data) { return wlan_sm_dispatch(vdev_mlme->sm_hdl, event,event_data_len, event_data); }
事件变迁
static void mlme_vdev_sm_transition_to(struct vdev_mlme_obj *vdev_mlme, enum wlan_vdev_state state) { wlan_sm_transition_to(vdev_mlme->sm_hdl, state); }
保存状态机历史
上面我们注意到在状态机变迁或者事件分发函数中会有 wlan_sm_save_history(sm, SM_EVENT_MSG_PROCESSING, sm->cur_state,sm->cur_state, event)函数调用,
该函数就是用来保存状态机历史的,历史可以直接输出到屏幕,也可以保存到文件,下面以保存到文件为例说明:
基本结构体
enum wlan_sm_trace_type {
SM_EVENT_STATE_TRANSITION = 1, // 在传输函数中 调用保存
SM_EVENT_MSG_PROCESSING, // 在事件通知函数中 调用保存
};
struct wlan_sm_history_info {
enum wlan_sm_trace_type trace_type; // 类型 参见enum wlan_sm_trace_type
uint8_t event_type; // 事件类型
uint8_t initial_state; // 当前状态 Current state (state/sub-state)
uint8_t final_state; // 新状态
uint64_t time; // 事件戳
};
/**
* struct wlan_sm_history - history structure
* @sm_history_lock: SM history lock
* @index: Last updated entry index
* @data: Histoy elements array
*/
struct wlan_sm_history {
qdf_spinlock_t sm_history_lock;
uint8_t index; // 索引,默认最大50个 最大值参见 WLAN_SM_ENGINE_HISTORY_SIZE
struct wlan_sm_history_info data[WLAN_SM_ENGINE_HISTORY_SIZE]; // 一共
};
解释:相当于定义了50个信息 struct wlan_sm_history_info结构体数组,然后保存一次,index++,最大的时候轮回。
api函数
保存到历史
void wlan_sm_save_history(struct wlan_sm *sm, enum wlan_sm_trace_type trace_type, uint8_t initial_state, uint8_t final_state, uint16_t event_type) { struct wlan_sm_history *p_sm_history = &sm->history; struct wlan_sm_history_info *p_memento; /* * History saved in circular buffer. * Save a pointer to next write location and increment pointer. */ qdf_spin_lock_bh(&p_sm_history->sm_history_lock); // 取出一个 data内存 p_memento = &p_sm_history->data[p_sm_history->index]; // 索引++ 并限幅 p_sm_history->index++; p_sm_history->index %= WLAN_SM_ENGINE_HISTORY_SIZE; qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); // 存放内容到 data内存中 qdf_mem_zero(p_memento, sizeof(*p_memento)); p_memento->trace_type = trace_type; p_memento->initial_state = initial_state; p_memento->final_state = final_state; p_memento->event_type = event_type; p_memento->time = qdf_get_log_timestamp(); }
直接打印历史
void wlan_sm_print_history(struct wlan_sm *sm) { struct wlan_sm_history *p_sm_history = &sm->history; uint8_t i; uint8_t idx; /* * History saved in circular buffer. * Save a pointer to next write location and increment pointer. */ qdf_spin_lock_bh(&p_sm_history->sm_history_lock); // 从当前p_sm_history->index 开始,轮询打印 每个p_sm_history->data[idx]里面的内容 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; wlan_sm_print_history_entry( sm, &p_sm_history->data[idx], idx); } qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); }
输出历史到文件
// 文件句柄 m哪里来 void wlan_sm_print_fs_history(struct wlan_sm *sm, qdf_debugfs_file_t m) { struct wlan_sm_history *p_sm_history = &sm->history; uint8_t i; uint8_t idx; /* * History saved in circular buffer. * Save a pointer to next write location and increment pointer. */ qdf_spin_lock_bh(&p_sm_history->sm_history_lock); // 从当前p_sm_history->index 开始,轮询输出 每个p_sm_history->data[idx]里面的内容到文件,那么是哪个文件,下面介绍 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; wlan_sm_print_fs_history_entry(sm, &p_sm_history->data[idx], idx, m); } qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); } static void wlan_sm_print_fs_history_entry(struct wlan_sm *sm, struct wlan_sm_history_info *ent, uint16_t i, qdf_debugfs_file_t m) { const char *event_name = NULL; qdf_debugfs_printf( m, "| 0x%016llx |%6d |%11d |%28d |%19s[%2d] |%19s[%2d] |\n", ent->time, i, ent->trace_type, ent->event_type, sm->state_info[ent->initial_state].name, ent->initial_state, sm->state_info[ent->final_state].name, ent->final_state); } // 该函数相当于写文件file void qdf_debugfs_printf(qdf_debugfs_file_t file, const char *f, ...) { va_list args; va_start(args, f); seq_vprintf(file, f, args); va_end(args); }
文件创建地方
static struct qdf_debugfs_fops sm_dbg_buf_fops = {
.show = sm_dbg_fs_open,
.write = sm_dbg_fs_write,
.priv = NULL,
};
qdf_dentry_t mlme_debugfs_entry;
static void wlan_sm_dbgfs_create(void)
{
mlme_debugfs_entry = qdf_debugfs_create_dir("wlan_mlme", NULL);
if (mlme_debugfs_entry) {
if (!qdf_debugfs_create_file_simplified("vdev_sm_history",
(QDF_FILE_USR_READ |
QDF_FILE_GRP_READ |
QDF_FILE_OTH_READ),
mlme_debugfs_entry,
&sm_dbg_buf_fops)) {
qdf_err("debugfs entry creation failed!");
return;
}
}
}
// 这里用了内核的 debugfs_create_file 相关内容,这里不做过多解释
// 总之会 在 /sys/kernel/debug/qdf/wlan_mlme 下创建 vdev_sm_history状态机,
