From a8878c34c747769c7a069910d26d94de4efac03c Mon Sep 17 00:00:00 2001 From: Star Chang Date: Tue, 27 Sep 2022 03:50:03 +0000 Subject: wlan_ptracker: add dumpstate support 1. add support dumpstate 2. fix kernel exception issue Bug: 253348062 Test: ST-stability/WiFi regression/WiFi performance Test pass Signed-off-by: Star Chang Change-Id: I55610531fbe21f870d28605b077b3adce742ed47 --- debugfs.c | 21 ++++++- debugfs.h | 3 + dynamic_twt_manager.c | 158 +++++++++++++++++++++++++++++++++++++------------- dynamic_twt_manager.h | 15 ++++- notifier.c | 4 ++ scenes_fsm.c | 13 +---- scenes_fsm.h | 2 - 7 files changed, 160 insertions(+), 56 deletions(-) diff --git a/debugfs.c b/debugfs.c index 3cf4dc4..6fe6d99 100644 --- a/debugfs.c +++ b/debugfs.c @@ -85,6 +85,20 @@ static const struct file_operations dscp_ops = { .llseek = generic_file_llseek, }; +static int wlan_ptracker_sysfs_init(struct wlan_ptracker_debugfs *debugfs) +{ + debugfs->kobj = kobject_create_and_add("wlan_ptracker", NULL); + if (!debugfs->kobj) + return -ENODEV; + return 0; +} + +static void wlan_ptracker_sysfs_exit(struct wlan_ptracker_debugfs *debugfs) +{ + if (debugfs->kobj) + kobject_put(debugfs->kobj); +} + int wlan_ptracker_debugfs_init(struct wlan_ptracker_debugfs *debugfs) { struct wlan_ptracker_core *core = container_of( @@ -96,6 +110,7 @@ int wlan_ptracker_debugfs_init(struct wlan_ptracker_debugfs *debugfs) debugfs_create_file("action", 0600, debugfs->root, core, &dscp_ops); debugfs_create_u32("dscp", 0600, debugfs->root, &debugfs->dscp); debugfs_create_u32("ac", 0600, debugfs->root, &debugfs->ac); + wlan_ptracker_sysfs_init(debugfs); return 0; } @@ -103,6 +118,7 @@ void wlan_ptracker_debugfs_exit(struct wlan_ptracker_debugfs *debugfs) { debugfs_remove_recursive(debugfs->root); debugfs->root = NULL; + wlan_ptracker_sysfs_exit(debugfs); } struct history_manager *wlan_ptracker_history_create(int entry_count, int entry_size) @@ -179,14 +195,13 @@ size_t wlan_ptracker_history_read(struct history_manager *hm, char *buf, int buf cur = (struct history_entry *) ptr; if (!cur->valid) break; - j = (i + hm->entry_count + 1) % hm->entry_count; + j = (i + 1) % hm->entry_count; next = (struct history_entry *)(hm->entries + (j * hm->entry_size)); len += scnprintf(buf + len, buf_len - len, "%02d: ", i); len += history_get_tm(cur, buf + len, buf_len - len); len += scnprintf(buf + len, buf_len - len, "%12s =>", state2str[cur->state]); if (hm->priv_read) - len += hm->priv_read(cur, next->valid ? next : NULL, buf + len, - buf_len - len); + len += hm->priv_read(cur, next, buf + len, buf_len - len); len += scnprintf(buf + len, buf_len - len, "\n"); ptr += hm->entry_size; } diff --git a/debugfs.h b/debugfs.h index 721cc49..2d4bfd4 100644 --- a/debugfs.h +++ b/debugfs.h @@ -11,9 +11,12 @@ #include #include #include +#include +#include struct wlan_ptracker_debugfs { struct dentry *root; + struct kobject *kobj; u32 dscp; u32 ac; u32 action; diff --git a/dynamic_twt_manager.c b/dynamic_twt_manager.c index e3f965a..2cf7aa3 100644 --- a/dynamic_twt_manager.c +++ b/dynamic_twt_manager.c @@ -18,16 +18,25 @@ static struct dytwt_manager dytwt_mgmt; #define DYMAIC_TWT_CONFIG_ID 3 /* for tcp one pair case */ -#define TWT_IDLE_INTERVAL (500 * 1024) /* 512000 */ -#define TWT_IDLE_DURATION (256 * 32) /* 16384 */ -#define TWT_WEB_INTERVAL (104 * 1024) /* 106496 */ -#define TWT_WEB_DURATION (256 * 32) /* 8192 */ -#define TWT_YOUTUBE_INTERVAL (10 * 1024) /* 10240 */ -#define TWT_YOUTUBE_DURATION (256 * 32) /* 8192 */ - -#define TWT_REASON_MAX (WLAN_PTRACKER_NOTIFY_MAX + 1) -static const char *const reason2str[WLAN_PTRACKER_NOTIFY_MAX] = { - "tp", "scene_change", "scene_prep", "suspend", "sta_change", +#define TWT_IDLE_INTERVAL (500 * 1024) /* 512000 */ +#define TWT_IDLE_DURATION (768 * 32) /* 24576 */ +#define TWT_WEB_INTERVAL (104 * 1024) /* 106496 */ +#define TWT_WEB_DURATION (256 * 32) /* 8192 */ +#define TWT_YOUTUBE_INTERVAL (10 * 1024) /* 10240 */ +#define TWT_YOUTUBE_DURATION (256 * 32) /* 8192 */ + +/* define reason*/ +enum { + TWT_SETUP_REASON_FRAMEWORK = WLAN_PTRACKER_NOTIFY_MAX, + TWT_SETUP_REASON_FORCE, + TWT_SETUP_REASON_RUNTIME, + TWT_SETUP_REASON_MAX, +}; + +static const char *const reason2str[TWT_SETUP_REASON_MAX] = { + "tp", "scene_change", "scene_prep", "suspend", "sta_connect", + "sta_discont", "dytwt_enable", "dytwt_disable", "framework", + "force", "runtime", }; static const char *const state2str[WLAN_SCENE_MAX] = { @@ -97,7 +106,7 @@ static struct dytwt_scene_action dytwt_actions[WLAN_SCENE_MAX + 1] = { static int dytwt_client_twt_setup(struct wlan_ptracker_client *client, u32 state) { - if (!client->dytwt_ops) + if (!client->dytwt_ops || !client->priv) return -EINVAL; if (!client->dytwt_ops->setup) @@ -111,7 +120,7 @@ static int dytwt_client_twt_setup(struct wlan_ptracker_client *client, u32 state static int dytwt_client_twt_teardown(struct wlan_ptracker_client *client, u32 state) { - if (!client->dytwt_ops) + if (!client->dytwt_ops || !client->priv) return -EINVAL; if (!client->dytwt_ops->teardown) @@ -119,7 +128,6 @@ static int dytwt_client_twt_teardown(struct wlan_ptracker_client *client, u32 st if (state >= WLAN_SCENE_MAX) return -EINVAL; - return client->dytwt_ops->teardown(client->priv, &dytwt_actions[state].param); } @@ -129,7 +137,7 @@ static bool dytwt_client_twt_cap(struct wlan_ptracker_client *client) struct dytwt_manager *dytwt = dytwt_get_manager(); int ret; - if (!client->dytwt_ops) + if (!client->dytwt_ops || !client->priv) return false; if (!client->dytwt_ops->get_cap) @@ -165,7 +173,7 @@ static bool dytwt_client_twt_cap(struct wlan_ptracker_client *client) static int dytwt_client_twt_pwrstates(struct wlan_ptracker_client *client, struct dytwt_pwr_state *state) { - if (!client->dytwt_ops) + if (!client->dytwt_ops || !client->priv) return -EINVAL; if (!client->dytwt_ops->get_pwrstates) @@ -177,7 +185,7 @@ static int dytwt_client_twt_pwrstates(struct wlan_ptracker_client *client, static int dytwt_client_twt_get_stats(struct wlan_ptracker_client *client, struct dytwt_stats *stats) { - if (!client->dytwt_ops) + if (!client->dytwt_ops || !client->priv) return -EINVAL; if (!client->dytwt_ops->get_stats) @@ -186,6 +194,18 @@ static int dytwt_client_twt_get_stats(struct wlan_ptracker_client *client, return client->dytwt_ops->get_stats(client->priv, stats); } +static int dytwt_client_twt_get_status(struct wlan_ptracker_client *client, + struct dytwt_status *status) +{ + if (!client->dytwt_ops || !client->priv) + return -EINVAL; + + if (!client->dytwt_ops->get_status) + return -EINVAL; + + return client->dytwt_ops->get_status(client->priv, status); +} + static inline void dytwt_record_get_pwr(u64 asleep, u64 awake, u64 *total, int *percent) { /* for percent */ @@ -220,7 +240,6 @@ static int dytwt_record_priv_read(void *cur, void *next, char *buf, int len) dytwt_record_get_pwr(c->pwr.asleep, c->pwr.awake, &total_time, &total_percent); } dytwt_record_get_pwr(asleep, awake, &period_time, &period_percent); - return scnprintf(buf, len, "Applied: %s, Time: %llu (%llu) ms, Percent: %d%% (%d%%) Reason: %s, Rate: %d", c->apply ? "TRUE" : "FALSE", period_time, total_time, period_percent, total_percent, @@ -245,8 +264,8 @@ static void dytwt_counter_update(struct dytwt_manager *dytwt, struct dytwt_pwr_s counter->total_sleep_cnt += count; } -static void dytwt_mgmt_history_store(struct wlan_ptracker_client *client, struct dytwt_manager *dytwt, - struct wlan_scene_event *msg, bool apply) +static void dytwt_mgmt_history_store(struct wlan_ptracker_client *client, + struct dytwt_manager *dytwt, struct wlan_scene_event *msg, bool apply, u32 reason) { struct dytwt_entry *entry; @@ -256,7 +275,7 @@ static void dytwt_mgmt_history_store(struct wlan_ptracker_client *client, struct return; /* record private values */ entry->apply = apply; - entry->reason = msg->reason; + entry->reason = reason; entry->rate = msg->rate; dytwt_client_twt_pwrstates(client, &entry->pwr); dytwt_counter_update(dytwt, &entry->pwr); @@ -282,20 +301,15 @@ static int _dytwt_scene_change_handler(struct dytwt_manager *dytwt, ptracker_dbg(dytwt->core, "twt is not supported on device or peer\n"); goto out; } - act = &dytwt_actions[state]; /* follow action to setup */ - if (act->action == TWT_ACTION_SETUP) { + if (act->action == TWT_ACTION_SETUP) ret = dytwt_client_twt_setup(client, state); - } else { - /* tear down was applied at state of "perpare_change". */ - apply = true; - } apply = ret ? false : true; out: /* store record of history even twt is not applied */ - dytwt_mgmt_history_store(client, dytwt, msg, apply); + dytwt_mgmt_history_store(client, dytwt, msg, apply, msg->reason); ptracker_dbg(dytwt->core, "twt setup for state: %d, reason: %s, ret: %d\n", state, reason2str[msg->reason], ret); return ret; @@ -312,11 +326,16 @@ static void dytwt_delay_setup(struct work_struct *work) rcu_read_lock(); client = rcu_dereference(core->client); + if (!client) + goto end; + /* for first time update value is required*/ + dytwt->twt_cap = dytwt_client_twt_cap(client); _dytwt_scene_change_handler(dytwt, client); +end: rcu_read_unlock(); } -#define TWT_WAIT_STA_READY_TIME 1000 +#define TWT_WAIT_STA_READY_TIME 2000 static int dytwt_scene_change_handler(struct wlan_ptracker_client *client) { struct dytwt_manager *dytwt = dytwt_get_manager(); @@ -355,7 +374,8 @@ static const struct file_operations twt_ops = { .llseek = generic_file_llseek, }; -static void dytwt_force_twt_setup(struct wlan_ptracker_client *client, struct dytwt_manager *dytwt) +static void dytwt_force_twt_setup(struct wlan_ptracker_client *client, struct dytwt_manager *dytwt, + u32 reason) { int ret = 0; bool apply = false; @@ -376,10 +396,10 @@ static void dytwt_force_twt_setup(struct wlan_ptracker_client *client, struct dy apply = ret ? false : true; msg.dst = dytwt->state; /* store record of history even twt is not applied */ - dytwt_mgmt_history_store(client, dytwt, &msg, apply); + dytwt_mgmt_history_store(client, dytwt, &msg, apply, reason); } -static inline void twt_enable(struct wlan_ptracker_client *client, bool enable) +static inline void twt_enable(struct wlan_ptracker_client *client, bool enable, u32 reason) { struct dytwt_manager *dytwt = dytwt_get_manager(); @@ -388,7 +408,7 @@ static inline void twt_enable(struct wlan_ptracker_client *client, bool enable) dytwt_scene_change_handler(client); } else { dytwt->state = WLAN_SCENE_TPUT; - dytwt_force_twt_setup(client, dytwt); + dytwt_force_twt_setup(client, dytwt, reason); dytwt->feature_flag &= ~BIT(FEATURE_FLAG_TWT); } } @@ -413,10 +433,12 @@ static void dytwt_runtime(struct work_struct *work) goto unlock; act = &dytwt_actions[dytwt->prev]; - if (act->action == TWT_ACTION_SETUP && !dytwt_client_twt_cap(client)) { + /* update twt_cap periodically */ + dytwt->twt_cap = dytwt_client_twt_cap(client); + if (act->action == TWT_ACTION_SETUP && !dytwt->twt_cap) { dytwt->state = WLAN_SCENE_TPUT; ptracker_dbg(dytwt->core, "teardown twt due to hit threshold\n"); - dytwt_force_twt_setup(client, dytwt); + dytwt_force_twt_setup(client, dytwt, TWT_SETUP_REASON_RUNTIME); } unlock: rcu_read_unlock(); @@ -426,7 +448,8 @@ end: static void update_twt_flag(struct wlan_ptracker_core *core, struct dytwt_manager *dytwt) { - twt_enable(core->client, !(dytwt->feature_flag & BIT(FEATURE_FLAG_TWT))); + twt_enable(core->client, !(dytwt->feature_flag & BIT(FEATURE_FLAG_TWT)), + TWT_SETUP_REASON_FORCE); } static void update_twt_parameters(struct dytwt_manager *dytwt) @@ -464,6 +487,21 @@ static void dytwt_stats_dump(struct wlan_ptracker_client *client, struct dytwt_m stats.sp_seq, stats.eosp_count, stats.eosp_dur_avg); } +static void dytwt_status_dump(struct wlan_ptracker_client *client, struct dytwt_manager *dytwt) +{ + struct dytwt_status status; + + status.config_id = DYMAIC_TWT_CONFIG_ID; + dytwt_client_twt_get_status(client, &status); + + ptracker_info(dytwt->core, "config_id: %d, flow_id: %d, flow_flags: %x\n", + status.config_id, status.flow_id, status.flow_flags); + ptracker_info(dytwt->core, "setup_cmd: %d, channel: %d, nego_type: %d\n", + status.setup_cmd, status.channel, status.nego_type); + ptracker_info(dytwt->core, "wake_dur: %d, wake_int: %d\n", + status.wake_dur, status.wake_int); +} + static int dytwt_debugfs_action(struct wlan_ptracker_core *core, u32 action) { struct dytwt_pwr_state pwr_state; @@ -478,7 +516,7 @@ static int dytwt_debugfs_action(struct wlan_ptracker_core *core, u32 action) switch (action) { case TWT_TEST_FORCE_STATE: - dytwt_force_twt_setup(client, dytwt); + dytwt_force_twt_setup(client, dytwt, TWT_SETUP_REASON_FORCE); break; case TWT_TEST_CAP: dytwt_client_twt_cap(client); @@ -495,6 +533,9 @@ static int dytwt_debugfs_action(struct wlan_ptracker_core *core, u32 action) case TWT_TEST_DUMP_STATS: dytwt_stats_dump(client, dytwt); break; + case TWT_TEST_DUMP_STATUS: + dytwt_status_dump(client, dytwt); + break; default: ptracker_err(core, "action %d is not supported!\n", action); return -ENOTSUPP; @@ -635,7 +676,10 @@ static void dytwt_scene_change_prepare_handler(struct wlan_ptracker_client *clie if (!(dytwt->feature_flag & BIT(FEATURE_FLAG_TWT))) return; - /* prepare to change state teardown original setup first */ + /* + * prepare to change state, teardown the original setup first. + * This change is not recorded in history. + */ if (dytwt_actions[prev_state].action == TWT_ACTION_SETUP) dytwt_client_twt_teardown(client, dytwt->prev); } @@ -665,10 +709,10 @@ static int dytwt_notifier_handler(struct notifier_block *nb, unsigned long event cancel_delayed_work_sync(&dytwt->wq); break; case WLAN_PTRACKER_NOTIFY_DYTWT_ENABLE: - twt_enable(client, true); + twt_enable(client, true, TWT_SETUP_REASON_FRAMEWORK); break; case WLAN_PTRACKER_NOTIFY_DYTWT_DISABLE: - twt_enable(client, false); + twt_enable(client, false, TWT_SETUP_REASON_FRAMEWORK); break; default: break; @@ -678,6 +722,35 @@ unlock: return NOTIFY_OK; } +static ssize_t dytwt_dumpstate_statistic(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return dytwt_statistic_read(buf, PAGE_SIZE); +} + +static ssize_t dytwt_dumpstate_history(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct dytwt_manager *dytwt = dytwt_get_manager(); + return wlan_ptracker_history_read(dytwt->hm, buf, PAGE_SIZE); +} + +static struct kobj_attribute attr_twt_history = + __ATTR(twt_history, 0664, dytwt_dumpstate_history, NULL); + +static struct kobj_attribute attr_twt_statistic = + __ATTR(twt_statistic, 0664, dytwt_dumpstate_statistic, NULL); + +static struct attribute *default_file_attrs[] = { + &attr_twt_history.attr, + &attr_twt_statistic.attr, + NULL, +}; + +static const struct attribute_group attr_group = { + .attrs = default_file_attrs, +}; + static int dytwt_debugfs_init(struct wlan_ptracker_core *core) { struct wlan_ptracker_debugfs *debugfs = &core->debugfs; @@ -697,17 +770,22 @@ static int dytwt_debugfs_init(struct wlan_ptracker_core *core) debugfs_create_u32("wake_duration", 0666, dytwt->dir, &act->param.wake_duration); debugfs_create_u32("action", 0666, dytwt->dir, &act->action); debugfs_create_u32("feature_flag", 0666, dytwt->dir, &dytwt->feature_flag); + if (debugfs->kobj) + sysfs_create_group(debugfs->kobj, &attr_group); return 0; } -#define TWT_DEFAULT_MIN_LINK_SPEED (90000) +#define TWT_DEFAULT_MIN_LINK_SPEED (180000) #define TWT_DEFAULT_MIN_RSSI (-70) #define DYTWT_RECORD_MAX 30 static int dytwt_mgmt_init(struct wlan_ptracker_core *core) { struct dytwt_manager *dytwt = dytwt_get_manager(); + struct wlan_ptracker_debugfs *debugfs = &core->debugfs; struct history_manager *hm; + if (debugfs->kobj) + sysfs_remove_group(debugfs->kobj, &attr_group); if (dytwt->dir) debugfs_remove_recursive(dytwt->dir); memset(dytwt, 0, sizeof(*dytwt)); diff --git a/dynamic_twt_manager.h b/dynamic_twt_manager.h index a7ecd55..43cdf21 100644 --- a/dynamic_twt_manager.h +++ b/dynamic_twt_manager.h @@ -35,6 +35,17 @@ struct dytwt_pwr_state { u64 count; }; +struct dytwt_status { + u32 config_id; + u32 flow_id; + u32 flow_flags; + u32 setup_cmd; + u32 channel; + u32 nego_type; + u32 wake_dur; + u32 wake_int; +}; + struct dytwt_stats { u32 config_id; u32 sp_seq; /* sequence number of the service period */ @@ -60,6 +71,7 @@ struct dytwt_client_ops { int (*get_cap)(void *priv, struct dytwt_cap *cap); int (*get_pwrstates)(void *priv, struct dytwt_pwr_state *state); int (*get_stats)(void *priv, struct dytwt_stats *stats); + int (*get_status)(void *priv, struct dytwt_status *status); }; enum { @@ -75,6 +87,7 @@ enum { TWT_TEST_ONOFF, TWT_TEST_SET_PARAM, TWT_TEST_DUMP_STATS, + TWT_TEST_DUMP_STATUS, TWT_TEST_MAX, }; @@ -116,6 +129,7 @@ struct dytwt_manager { struct history_manager *hm; u32 rssi_threshold; u32 link_threshold; + bool twt_cap; struct delayed_work wq; struct delayed_work setup_wq; struct wlan_ptracker_core *core; @@ -125,5 +139,4 @@ struct dytwt_manager { extern int dytwt_init(struct wlan_ptracker_core *core); extern void dytwt_exit(struct wlan_ptracker_core *core); - #endif /* __TP_TRACKER_DYNAMIC_TWT_SETUP_H */ diff --git a/notifier.c b/notifier.c index 7f9712d..01dd768 100644 --- a/notifier.c +++ b/notifier.c @@ -18,16 +18,20 @@ static int up_event_handler(struct wlan_ptracker_core *core, struct net_device * { core->dev = dev; core->client->core = core; + dev_hold(dev); core->client->priv = dev; return tp_monitor_init(&core->tp); } static void down_event_handler(struct wlan_ptracker_core *core) { + struct net_device *dev = core->dev; tp_monitor_exit(&core->tp); core->dev = NULL; core->client->core = NULL; core->client->priv = NULL; + if (dev) + dev_put(dev); } static int netdevice_notifier_handler(struct notifier_block *nb, diff --git a/scenes_fsm.c b/scenes_fsm.c index 768c75d..6bb920c 100644 --- a/scenes_fsm.c +++ b/scenes_fsm.c @@ -58,15 +58,12 @@ static int fsm_thread(void *param) break; } wait_for_completion(&fsm->event); + ptracker_dbg(core, "state: %d, trans state %d -> %d, rate %llu\n", msg->state, msg->src, msg->dst, msg->rate); - wlan_ptracker_call_chain(&core->notifier, - WLAN_PTRACKER_NOTIFY_SCENE_CHANGE_PREPARE, core); - fsm->confirm = true; - wlan_ptracker_call_chain(&core->notifier, - WLAN_PTRACKER_NOTIFY_SCENE_CHANGE, core); + wlan_ptracker_call_chain(&core->notifier, WLAN_PTRACKER_NOTIFY_SCENE_CHANGE_PREPARE, core); + wlan_ptracker_call_chain(&core->notifier, WLAN_PTRACKER_NOTIFY_SCENE_CHANGE, core); msg->state = msg->dst; - fsm->confirm = false; } return 0; } @@ -171,7 +168,6 @@ static int scene_notifier_handler(struct notifier_block *nb, { struct wlan_ptracker_core *core = ptr; struct wlan_ptracker_notifier *notifier = &core->notifier; - struct wlan_ptracker_fsm *fsm = &core->fsm; /* * Events of suspen and sta change will block wlan driver @@ -186,7 +182,6 @@ static int scene_notifier_handler(struct notifier_block *nb, notifier->prev_event = jiffies; case WLAN_PTRACKER_NOTIFY_STA_CONNECT: case WLAN_PTRACKER_NOTIFY_TP: - fsm->confirm = true; scenes_fsm_decision(core, event); break; default: @@ -310,8 +305,6 @@ int scenes_fsm_init(struct wlan_ptracker_fsm *fsm) /* assign scenes and conditions */ fsm->conditions = &conditions[0]; fsm->reset_cnt = 0; - /* for first link up setting */ - fsm->confirm = true; /* init msg for receiving event */ msg->dst = WLAN_SCENE_IDLE; msg->src = WLAN_SCENE_IDLE; diff --git a/scenes_fsm.h b/scenes_fsm.h index 49b1a23..e7aa284 100644 --- a/scenes_fsm.h +++ b/scenes_fsm.h @@ -60,7 +60,6 @@ struct wlan_scene_event { struct wlan_ptracker_fsm { int reset_cnt; - bool confirm; bool thread_run; struct completion event; struct wlan_scene_event msg; @@ -76,5 +75,4 @@ struct wlan_ptracker_fsm { extern int scenes_fsm_init(struct wlan_ptracker_fsm *fsm); extern void scenes_fsm_exit(struct wlan_ptracker_fsm *fsm); - #endif /* __WLAN_SCENES_FSM_H */ -- cgit v1.2.3