mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 08:36:12 -04:00
qcacmn: Implement State machine framework
This is generic state machine framework, which provides APIs for state definition, state transition, event posting Change-Id: Ie7d5a064967098fcb77a663047c479d1d1576595 CRs-Fixed: 2307722
This commit is contained in:
parent
2ae5e4c142
commit
bc7748c852
6 changed files with 864 additions and 0 deletions
|
|
@ -360,6 +360,7 @@ typedef void (*qdf_timer_func_t)(void *);
|
|||
* @QDF_MODULE_ID_TARGET: Target module ID
|
||||
* @QDF_MODULE_ID_MBSSIE: MBSS IE ID
|
||||
* @QDF_MODULE_ID_FWOL: FW Offload module ID
|
||||
* @QDF_MODULE_ID_SM_ENGINE: SM engine module ID
|
||||
* @QDF_MODULE_ID_ANY: anything
|
||||
* @QDF_MODULE_ID_MAX: Max place holder module ID
|
||||
*/
|
||||
|
|
@ -467,6 +468,7 @@ typedef enum {
|
|||
QDF_MODULE_ID_TARGET,
|
||||
QDF_MODULE_ID_MBSSIE,
|
||||
QDF_MODULE_ID_FWOL,
|
||||
QDF_MODULE_ID_SM_ENGINE,
|
||||
QDF_MODULE_ID_ANY,
|
||||
QDF_MODULE_ID_MAX,
|
||||
} QDF_MODULE_ID;
|
||||
|
|
|
|||
|
|
@ -2834,6 +2834,7 @@ struct category_name_info g_qdf_category_name[MAX_SUPPORTED_CATEGORY] = {
|
|||
[QDF_MODULE_ID_TARGET] = {"TARGET"},
|
||||
[QDF_MODULE_ID_MBSSIE] = {"MBSSIE"},
|
||||
[QDF_MODULE_ID_FWOL] = {"fwol"},
|
||||
[QDF_MODULE_ID_SM_ENGINE] = {"SM_ENGINE"},
|
||||
[QDF_MODULE_ID_ANY] = {"ANY"},
|
||||
};
|
||||
qdf_export_symbol(g_qdf_category_name);
|
||||
|
|
@ -3283,6 +3284,7 @@ static void set_default_trace_levels(struct category_info *cinfo)
|
|||
[QDF_MODULE_ID_CP_STATS] = QDF_TRACE_LEVEL_ERROR,
|
||||
[QDF_MODULE_ID_MBSSIE] = QDF_TRACE_LEVEL_INFO,
|
||||
[QDF_MODULE_ID_FWOL] = QDF_TRACE_LEVEL_NONE,
|
||||
[QDF_MODULE_ID_SM_ENGINE] = QDF_TRACE_LEVEL_DEBUG,
|
||||
[QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO,
|
||||
};
|
||||
|
||||
|
|
|
|||
268
umac/cmn_services/sm_engine/inc/wlan_sm_engine.h
Normal file
268
umac/cmn_services/sm_engine/inc/wlan_sm_engine.h
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Define general SM framework, The modules can implement state machine
|
||||
* using framework, it provides framework for state, event, state transition,
|
||||
* event handling
|
||||
*
|
||||
* The module, whoever implement SM using this framework need to define an array
|
||||
* of structures (of type struct wlan_sm_state_info) as below,
|
||||
* for example, sample state array definition
|
||||
*
|
||||
* 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, --> gets invoked on entering the state
|
||||
* mlme_vdev_state_init_exit, --> gets invoked before exiting the state
|
||||
* mlme_vdev_state_init_event --> gets invoked on event dispatch
|
||||
* },
|
||||
* {
|
||||
* (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
|
||||
* },
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* Invoke wlan_sm_create() with this state array as below
|
||||
*
|
||||
* sm = wlan_sm_create("VDEV_SM", vdev_obj, WLAN_VDEV_S_INIT, sm_info, 3,
|
||||
* event_names[], num_events);
|
||||
*
|
||||
* on successful creation, invoke below functions to dispatch events and state
|
||||
* transition
|
||||
*
|
||||
* Event dispatch:
|
||||
* wlan_sm_dispatch(sm, start_event_id, 0, NULL);
|
||||
*
|
||||
* State transition:
|
||||
* wlan_sm_transition_to(sm, WLAN_VDEV_S_INIT);
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef _WLAN_SM_ENGINE_H_
|
||||
#define _WLAN_SM_ENGINE_H_
|
||||
|
||||
#include <qdf_types.h>
|
||||
#include <qdf_atomic.h>
|
||||
#include <wlan_sm_engine_dbg.h>
|
||||
|
||||
/* invalid state */
|
||||
#define WLAN_SM_ENGINE_STATE_NONE 255
|
||||
/* invalid event */
|
||||
#define WLAN_SM_ENGINE_EVENT_NONE 255
|
||||
|
||||
#define WLAN_SM_ENGINE_MAX_STATE_NAME 128
|
||||
#define WLAN_SM_ENGINE_MAX_NAME 64
|
||||
#define WLAN_SM_ENGINE_MAX_STATES 200
|
||||
#define WLAN_SM_ENGINE_MAX_EVENTS 200
|
||||
|
||||
/**
|
||||
* struct wlan_sm_state_info - state structure definition
|
||||
* @state: State id
|
||||
* @parent_state: Parent state id (optional)
|
||||
* @initial_substate: Initial sub state of this state
|
||||
* @has_substates: flag to specify, whether it has sub states
|
||||
* @name: Name of the state
|
||||
* @wlan_sm_entry: State entry callback poitner
|
||||
* @wlan_sm_exit: State exit callback poitner
|
||||
* @wlan_sm_event: State event callback poitner
|
||||
*/
|
||||
struct 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);
|
||||
void (*wlan_sm_exit) (void *ctx);
|
||||
bool (*wlan_sm_event) (void *ctx, uint16_t event,
|
||||
uint16_t event_data_len, void *event_data);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wlan_sm - state machine structure
|
||||
* @name: Name of the statemachine
|
||||
* @cur_state: Current state (state/sub-state)
|
||||
* @num_states: Number of states
|
||||
* @last_event: Holds the last handled event of SM
|
||||
* @state_info: Initialized States' table
|
||||
* @ctx: Holds the caller's context
|
||||
* @in_state_transition: Flag to check whether state transition is in progress
|
||||
* @event_names: Array of event names
|
||||
* @num_event_names: Number of event names
|
||||
* @history: Holds the SM history pointer
|
||||
*/
|
||||
struct 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;
|
||||
void *ctx;
|
||||
qdf_atomic_t in_state_transition;
|
||||
const char **event_names;
|
||||
uint32_t num_event_names;
|
||||
#ifdef SM_ENG_HIST_ENABLE
|
||||
struct wlan_sm_history history;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define WLAN_SM_ENGINE_ENTRY(name, state, parent, initsubstate, has_substates) \
|
||||
{ state, parent, initsubstate, has_substates, \
|
||||
"##name", wlan_sm_##name_entry, wlan_sm_##name_exit,\
|
||||
wlan_sm_##name_event }
|
||||
|
||||
/*
|
||||
* flag definitions
|
||||
*/
|
||||
#define WLAN_SM_ENGINE_ASYNCHRONOUS 0x0 /* run SM asynchronously */
|
||||
#define WLAN_SM_ENGINE_SYNCHRONOUS 0x1 /* run SM synchronously */
|
||||
|
||||
/**
|
||||
* wlan_sm_create() - SM create
|
||||
* @name: Name of SM owner module
|
||||
* @ctx: caller pointer, used on invoking callbacks
|
||||
* @init_state: Default state of the SM
|
||||
* @state_info: States' definitions
|
||||
* @num_state: Number of states
|
||||
* @event_names: Event name table
|
||||
* @num_event_names: Number of events
|
||||
*
|
||||
* Creates SM object, intializes with init_state, stores the name and owner
|
||||
* module pointer, states definition table, and event name table
|
||||
*
|
||||
* Return: Handle to struct wlan_sm on successful creation,
|
||||
* NULL on Failure
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* wlan_sm_delete() - SM delete
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Delete SM object
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_delete(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_dispatch() - API to notify event to SM
|
||||
* @sm: state machine handle
|
||||
* @event: event id
|
||||
* @event_data_len: Size of event data
|
||||
* @event_data: Event data
|
||||
*
|
||||
* Notifies event to SM, it invokes event callback of the current state of SM
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS for handling
|
||||
* QDF_STATUS_E_INVAL for not handling
|
||||
*/
|
||||
QDF_STATUS wlan_sm_dispatch(struct wlan_sm *sm, uint16_t event,
|
||||
uint16_t event_data_len, void *event_data);
|
||||
|
||||
/**
|
||||
* wlan_sm_transition_to() - API to move the state of SM
|
||||
* @sm: state machine handle
|
||||
* @state: State id
|
||||
*
|
||||
* Moves the SM's state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_transition_to(struct wlan_sm *sm, uint8_t state);
|
||||
|
||||
/**
|
||||
* wlan_sm_get_lastevent() - API to get last dispatched event
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Gets the last dispatched event
|
||||
*
|
||||
* Return: event id
|
||||
*/
|
||||
uint8_t wlan_sm_get_lastevent(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_get_current_state() - API to get current state of SM
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Gets the current state of SM
|
||||
*
|
||||
* Return: state id
|
||||
*/
|
||||
uint8_t wlan_sm_get_current_state(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_get_current_state_name() - API to get current state's name of SM
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Gets the current state name of SM
|
||||
*
|
||||
* Return: name of the state
|
||||
*/
|
||||
const char *wlan_sm_get_current_state_name(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_get_state_name() - API to get state's name
|
||||
* @sm: state machine handle
|
||||
* @state: state id
|
||||
*
|
||||
* Gets the given state name of SM
|
||||
*
|
||||
* Return: name of the state
|
||||
*/
|
||||
const char *wlan_sm_get_state_name(struct wlan_sm *sm, uint8_t state);
|
||||
|
||||
/**
|
||||
* wlan_sm_reset() - API to reset SM state
|
||||
* @sm: state machine handle
|
||||
* @init_state: state to reset SM
|
||||
*
|
||||
* Resets the SM to given state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_reset(struct wlan_sm *sm, uint8_t init_state);
|
||||
|
||||
#endif
|
||||
188
umac/cmn_services/sm_engine/inc/wlan_sm_engine_dbg.h
Normal file
188
umac/cmn_services/sm_engine/inc/wlan_sm_engine_dbg.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* DOC: Define the debug data structure of UMAC SM
|
||||
*/
|
||||
#ifndef _WLAN_SM_ENGINE_DBG_H_
|
||||
#define _WLAN_SM_ENGINE_DBG_H_
|
||||
|
||||
#include <qdf_types.h>
|
||||
#include <qdf_trace.h>
|
||||
|
||||
#define sm_engine_alert(params...) \
|
||||
QDF_TRACE_FATAL(QDF_MODULE_ID_SM_ENGINE, params)
|
||||
|
||||
#define sm_engine_err(params...) \
|
||||
QDF_TRACE_ERROR(QDF_MODULE_ID_SM_ENGINE, params)
|
||||
|
||||
#define sm_engine_warn(params...) \
|
||||
QDF_TRACE_WARN(QDF_MODULE_ID_SM_ENGINE, params)
|
||||
|
||||
#define sm_engine_info(params...) \
|
||||
QDF_TRACE_INFO(QDF_MODULE_ID_SM_ENGINE, params)
|
||||
|
||||
#define sm_engine_debug(params...) \
|
||||
QDF_TRACE_DEBUG(QDF_MODULE_ID_SM_ENGINE, params)
|
||||
|
||||
#define WLAN_SM_ENGINE_HISTORY_SIZE 50
|
||||
struct wlan_sm;
|
||||
/**
|
||||
* enum wlan_sm_trace_type - history element type
|
||||
* @SM_EVENT_STATE_TRANSITION - Represents state transition
|
||||
* @SM_EVENT_MSG_PROCESSING - Represents event processing
|
||||
*/
|
||||
enum wlan_sm_trace_type {
|
||||
SM_EVENT_STATE_TRANSITION = 1,
|
||||
SM_EVENT_MSG_PROCESSING,
|
||||
};
|
||||
|
||||
#ifdef SM_ENG_HIST_ENABLE
|
||||
|
||||
/**
|
||||
* struct wlan_sm_history_info - history element structure
|
||||
* @trace_type: history element type
|
||||
* @event_type: Type of the event
|
||||
* @initial_state: Current state (state/sub-state)
|
||||
* @final_state: New state
|
||||
*/
|
||||
struct wlan_sm_history_info {
|
||||
enum wlan_sm_trace_type trace_type;
|
||||
uint16_t event_type;
|
||||
uint8_t initial_state;
|
||||
uint8_t final_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
int index;
|
||||
struct wlan_sm_history_info data[WLAN_SM_ENGINE_HISTORY_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* wlan_sm_save_history() - API to save SM history
|
||||
* @sm: state machine handle
|
||||
* @trace_type: type of operation
|
||||
* @initial_state: current state
|
||||
* @final_state: Resultant state
|
||||
* @event_type: Event id
|
||||
*
|
||||
* Stores the SM state transition and event processing
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* wlan_sm_history_init() - API to initialize SM history module
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Initializes SM history module
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_history_init(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_history_delete() - API to delete SM history module
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Deletes SM history module
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_history_delete(struct wlan_sm *sm);
|
||||
|
||||
/**
|
||||
* wlan_sm_print_history() - API to print SM history
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Prints SM history
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void wlan_sm_print_history(struct wlan_sm *sm);
|
||||
|
||||
#else /* SM_ENG_HIST_ENABLE */
|
||||
|
||||
/**
|
||||
* wlan_sm_save_history() - API to save SM history
|
||||
* @sm: state machine handle
|
||||
* @trace_type: type of operation
|
||||
* @initial_state: current state
|
||||
* @final_state: Resultant state
|
||||
* @event_type: Event id
|
||||
*
|
||||
* Stores the SM state transition and event processing
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static inline 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)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_sm_history_init() - API to initialize SM history module
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Initializes SM history module
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static inline void wlan_sm_history_init(struct wlan_sm *sm)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_sm_history_delete() - API to delete SM history module
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Deletes SM history module
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static inline void wlan_sm_history_delete(struct wlan_sm *sm)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* wlan_sm_print_history() - API to print SM history
|
||||
* @sm: state machine handle
|
||||
*
|
||||
* Prints SM history
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static inline void wlan_sm_print_history(struct wlan_sm *sm)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* SM_ENG_HIST_ENABLE */
|
||||
#endif /* _WLAN_SM_ENGINE_DBG_H_ */
|
||||
319
umac/cmn_services/sm_engine/src/wlan_sm_engine.c
Normal file
319
umac/cmn_services/sm_engine/src/wlan_sm_engine.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Implements general SM framework
|
||||
*/
|
||||
|
||||
#include "wlan_sm_engine.h"
|
||||
#include "wlan_sm_engine_dbg.h"
|
||||
#include <qdf_module.h>
|
||||
#include <qdf_mem.h>
|
||||
#include <qdf_str.h>
|
||||
|
||||
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;
|
||||
|
||||
if (!sm) {
|
||||
sm_engine_err("SM is NULL");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
state = sm->cur_state;
|
||||
|
||||
if (event == WLAN_SM_ENGINE_EVENT_NONE) {
|
||||
sm_engine_err("%s: invalid event %d", sm->name, event);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
sm->last_event = event;
|
||||
|
||||
wlan_sm_save_history(sm, SM_EVENT_MSG_PROCESSING, sm->cur_state,
|
||||
sm->cur_state, event);
|
||||
|
||||
if (sm->event_names) {
|
||||
if (event < sm->num_event_names)
|
||||
event_name = sm->event_names[event];
|
||||
|
||||
sm_engine_debug("%s: current state %s event %s[%d]",
|
||||
sm->name,
|
||||
sm->state_info[sm->cur_state].name,
|
||||
event_name ? event_name : "UNKNOWN_EVENT",
|
||||
event);
|
||||
} else {
|
||||
sm_engine_debug("%s: current state %s event %d",
|
||||
sm->name,
|
||||
sm->state_info[sm->cur_state].name,
|
||||
event);
|
||||
}
|
||||
|
||||
if (state != WLAN_SM_ENGINE_STATE_NONE) {
|
||||
event_handled = (*sm->state_info[state].wlan_sm_event) (
|
||||
sm->ctx, event, event_data_len, event_data);
|
||||
if (!event_handled) {
|
||||
sm_engine_err("%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;
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_dispatch);
|
||||
|
||||
void wlan_sm_transition_to(struct wlan_sm *sm, uint8_t state)
|
||||
{
|
||||
const struct wlan_sm_state_info *state_info = sm->state_info;
|
||||
uint8_t new_state;
|
||||
uint8_t old_state;
|
||||
uint8_t new_sub_st;
|
||||
uint8_t ol_sub_st;
|
||||
uint8_t cur_state;
|
||||
|
||||
if (!sm) {
|
||||
sm_engine_err("SM is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
cur_state = sm->cur_state;
|
||||
|
||||
/* cannot change state from state entry/exit routines */
|
||||
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
|
||||
*/
|
||||
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_debug("%s: transition(state) %s => %s",
|
||||
sm->name, state_info[old_state].name,
|
||||
state_info[new_state].name);
|
||||
sm_engine_debug("%s: transition(sub_state) %s => %s",
|
||||
sm->name,
|
||||
ol_sub_st ? state_info[ol_sub_st].name : "IDLE",
|
||||
new_sub_st ? state_info[new_sub_st].name : "IDLE");
|
||||
|
||||
/*
|
||||
* call the exit function(s) of the current state hierarchy
|
||||
* starting from substate.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* call the entry function(s) of the current state hierarchy
|
||||
* starting from superstate.
|
||||
*/
|
||||
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_debug("%s: Entering Initial sub state %s",
|
||||
sm->name, state_info[cur_state].name);
|
||||
}
|
||||
qdf_atomic_set(&sm->in_state_transition, 0);
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_transition_to);
|
||||
|
||||
void wlan_sm_reset(struct wlan_sm *sm, uint8_t init_state)
|
||||
{
|
||||
sm->cur_state = init_state;
|
||||
}
|
||||
|
||||
static QDF_STATUS wlan_sm_validate_state_info(const char *name,
|
||||
const struct wlan_sm_state_info *state_info,
|
||||
uint8_t i)
|
||||
{
|
||||
bool state_visited[WLAN_SM_ENGINE_MAX_STATES] = {false};
|
||||
uint8_t state, next_state;
|
||||
/*
|
||||
* make sure that the state definitions are in order
|
||||
*/
|
||||
if ((state_info[i].state >= WLAN_SM_ENGINE_MAX_STATES) ||
|
||||
(state_info[i].state != i)) {
|
||||
sm_engine_err("%s: entry %d has invalid state %d",
|
||||
name, i, state_info[i].state);
|
||||
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
/* detect if there is any loop in the hierarichy */
|
||||
state = state_info[i].state;
|
||||
while (state != WLAN_SM_ENGINE_STATE_NONE) {
|
||||
if (state_visited[state]) {
|
||||
sm_engine_err("%s: detected a loop with entry %d",
|
||||
name, i);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
state_visited[state] = true;
|
||||
next_state = state_info[state].parent_state;
|
||||
if (next_state != WLAN_SM_ENGINE_STATE_NONE) {
|
||||
if (!state_info[next_state].has_substates) {
|
||||
sm_engine_err(
|
||||
"%s: state %d is marked as parent of %d but is not a super state",
|
||||
name, next_state, state);
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
}
|
||||
state = next_state;
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (num_states > WLAN_SM_ENGINE_MAX_STATES) {
|
||||
sm_engine_err("%s: Num states exceeded", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* validate the state_info table.
|
||||
* the entries need to be valid and also
|
||||
* need to be in order.
|
||||
*/
|
||||
for (i = 0; i < num_states; ++i) {
|
||||
if (wlan_sm_validate_state_info(name, state_info, i) !=
|
||||
QDF_STATUS_SUCCESS) {
|
||||
sm_engine_err("%s: states validation failed", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
sm = qdf_mem_malloc(sizeof(*sm));
|
||||
if (!sm) {
|
||||
sm_engine_alert("%s: sm allocation failed", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlan_sm_history_init(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);
|
||||
|
||||
sm_engine_debug("%s: sm creation successful", name);
|
||||
|
||||
return sm;
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_create);
|
||||
|
||||
void wlan_sm_delete(struct wlan_sm *sm)
|
||||
{
|
||||
wlan_sm_history_delete(sm);
|
||||
qdf_mem_free(sm);
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_delete);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_get_current_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;
|
||||
}
|
||||
|
||||
qdf_export_symbol(wlan_sm_get_current_state_name);
|
||||
85
umac/cmn_services/sm_engine/src/wlan_sm_engine_dbg.c
Normal file
85
umac/cmn_services/sm_engine/src/wlan_sm_engine_dbg.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Implements general SM debug framework
|
||||
*/
|
||||
#include <wlan_sm_engine.h>
|
||||
#include <wlan_sm_engine_dbg.h>
|
||||
|
||||
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);
|
||||
p_memento = &p_sm_history->data[p_sm_history->index];
|
||||
p_sm_history->index++;
|
||||
|
||||
if (p_sm_history->index >= WLAN_SM_ENGINE_HISTORY_SIZE)
|
||||
p_sm_history->index = 0;
|
||||
|
||||
qdf_spin_unlock_bh(&p_sm_history->sm_history_lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void wlan_sm_history_init(struct wlan_sm *sm)
|
||||
{
|
||||
qdf_spinlock_create(&sm->history.sm_history_lock);
|
||||
}
|
||||
|
||||
void wlan_sm_history_delete(struct wlan_sm *sm)
|
||||
{
|
||||
qdf_spinlock_destroy(&sm->history.sm_history_lock);
|
||||
}
|
||||
|
||||
void wlan_sm_print_history(struct wlan_sm *sm)
|
||||
{
|
||||
struct wlan_sm_history *p_sm_history = &sm->history;
|
||||
struct wlan_sm_history_info *p_memento;
|
||||
uint16_t i;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
sm_engine_info(" SM History index is %d", p_sm_history->index);
|
||||
for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) {
|
||||
p_memento = &p_sm_history->data[i];
|
||||
sm_engine_info(" (%d) trace_type: %d, event: %d", i,
|
||||
p_memento->trace_type, p_memento->event_type);
|
||||
sm_engine_info(" (%d) initial state : %d, final state: %d", i,
|
||||
p_memento->initial_state,
|
||||
p_memento->final_state);
|
||||
}
|
||||
|
||||
qdf_spin_unlock_bh(&p_sm_history->sm_history_lock);
|
||||
}
|
||||
Loading…
Reference in a new issue