Loading drivers/net/wireless/ath/wil6210/cfg80211.c +4 −0 Original line number Diff line number Diff line Loading @@ -728,6 +728,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); } wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); __wil_down(wil); Loading Loading @@ -775,6 +777,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); rc = wmi_pcp_stop(wil); Loading drivers/net/wireless/ath/wil6210/debugfs.c +67 −0 Original line number Diff line number Diff line Loading @@ -1037,6 +1037,71 @@ static const struct file_operations fops_info = { .llseek = seq_lseek, }; /*---------recovery------------*/ /* mode = [manual|auto] * state = [idle|pending|running] */ static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; char buf[80]; int n; static const char * const sstate[] = {"idle", "pending", "running"}; n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", no_fw_recovery ? "manual" : "auto", sstate[wil->recovery_state]); n = min_t(int, n, sizeof(buf)); return simple_read_from_buffer(user_buf, count, ppos, buf, n); } static ssize_t wil_write_file_recovery(struct file *file, const char __user *buf_, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; static const char run_command[] = "run"; char buf[sizeof(run_command) + 1]; /* to detect "runx" */ ssize_t rc; if (wil->recovery_state != fw_recovery_pending) { wil_err(wil, "No recovery pending\n"); return -EINVAL; } if (*ppos != 0) { wil_err(wil, "Offset [%d]\n", (int)*ppos); return -EINVAL; } if (count > sizeof(buf)) { wil_err(wil, "Input too long, len = %d\n", (int)count); return -EINVAL; } rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); if (rc < 0) return rc; buf[rc] = '\0'; if (0 == strcmp(buf, run_command)) wil_set_recovery_state(wil, fw_recovery_running); else wil_err(wil, "Bad recovery command \"%s\"\n", buf); return rc; } static const struct file_operations fops_recovery = { .read = wil_read_file_recovery, .write = wil_write_file_recovery, .open = simple_open, }; /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { Loading Loading @@ -1148,6 +1213,7 @@ static const struct { {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, {"info", S_IRUGO, &fops_info}, {"recovery", S_IRUGO | S_IWUSR, &fops_recovery}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, Loading Loading @@ -1190,6 +1256,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), {}, }; Loading drivers/net/wireless/ath/wil6210/main.c +38 −8 Original line number Diff line number Diff line Loading @@ -25,9 +25,9 @@ #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 static bool no_fw_recovery; bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); Loading Loading @@ -191,17 +191,38 @@ static void wil_scan_timer_fn(ulong x) schedule_work(&wil->fw_error_worker); } static int wil_wait_for_recovery(struct wil6210_priv *wil) { if (wait_event_interruptible(wil->wq, wil->recovery_state != fw_recovery_pending)) { wil_err(wil, "Interrupt, canceling recovery\n"); return -ERESTARTSYS; } if (wil->recovery_state != fw_recovery_running) { wil_info(wil, "Recovery cancelled\n"); return -EINTR; } wil_info(wil, "Proceed with recovery\n"); return 0; } void wil_set_recovery_state(struct wil6210_priv *wil, int state) { wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__, wil->recovery_state, state); wil->recovery_state = state; wake_up_interruptible(&wil->wq); } static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wireless_dev *wdev = wil->wdev; wil_dbg_misc(wil, "fw error worker\n"); if (no_fw_recovery) return; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ Loading @@ -224,8 +245,13 @@ static void wil_fw_error_worker(struct work_struct *work) case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_MONITOR: wil_info(wil, "fw error recovery started (try %d)...\n", wil_info(wil, "fw error recovery requested (try %d)...\n", wil->recovery_count); if (!no_fw_recovery) wil->recovery_state = fw_recovery_running; if (0 != wil_wait_for_recovery(wil)) break; __wil_down(wil); __wil_up(wil); break; Loading Loading @@ -302,6 +328,7 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); if (!wil->wmi_wq) Loading Loading @@ -331,6 +358,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) { wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); del_timer_sync(&wil->scan_timer); cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); Loading Loading @@ -573,6 +601,7 @@ int wil_reset(struct wil6210_priv *wil) void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); wil->recovery_state = fw_recovery_pending; schedule_work(&wil->fw_error_worker); } Loading Loading @@ -724,6 +753,7 @@ int wil_down(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); rc = __wil_down(wil); mutex_unlock(&wil->mutex); Loading drivers/net/wireless/ath/wil6210/wil6210.h +11 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/timex.h> #include "wil_platform.h" extern bool no_fw_recovery; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" Loading Loading @@ -379,6 +380,12 @@ struct wil_sta_info { unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; }; enum { fw_recovery_idle = 0, fw_recovery_pending = 1, fw_recovery_running = 2, }; struct wil6210_priv { struct pci_dev *pdev; int n_msi; Loading @@ -389,8 +396,10 @@ struct wil6210_priv { u32 hw_version; struct wil_board *board; u8 n_mids; /* number of additional MIDs as reported by FW */ int recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_state; /* FW recovery state machine */ unsigned long last_fw_recovery; /* jiffies of last fw recovery */ wait_queue_head_t wq; /* for all wait_event() use */ /* profile */ u32 monitor_flags; u32 secure_pcp; /* create secure PCP? */ Loading Loading @@ -507,6 +516,7 @@ void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); void wil_set_itr_trsh(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); Loading drivers/net/wireless/ath/wil6210/wmi.c +1 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, { wil_dbg_wmi(wil, "WMI: got FW ready event\n"); wil_set_recovery_state(wil, fw_recovery_idle); set_bit(wil_status_fwready, &wil->status); /* let the reset sequence continue */ complete(&wil->wmi_ready); Loading Loading
drivers/net/wireless/ath/wil6210/cfg80211.c +4 −0 Original line number Diff line number Diff line Loading @@ -728,6 +728,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); } wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); __wil_down(wil); Loading Loading @@ -775,6 +777,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); rc = wmi_pcp_stop(wil); Loading
drivers/net/wireless/ath/wil6210/debugfs.c +67 −0 Original line number Diff line number Diff line Loading @@ -1037,6 +1037,71 @@ static const struct file_operations fops_info = { .llseek = seq_lseek, }; /*---------recovery------------*/ /* mode = [manual|auto] * state = [idle|pending|running] */ static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; char buf[80]; int n; static const char * const sstate[] = {"idle", "pending", "running"}; n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", no_fw_recovery ? "manual" : "auto", sstate[wil->recovery_state]); n = min_t(int, n, sizeof(buf)); return simple_read_from_buffer(user_buf, count, ppos, buf, n); } static ssize_t wil_write_file_recovery(struct file *file, const char __user *buf_, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; static const char run_command[] = "run"; char buf[sizeof(run_command) + 1]; /* to detect "runx" */ ssize_t rc; if (wil->recovery_state != fw_recovery_pending) { wil_err(wil, "No recovery pending\n"); return -EINVAL; } if (*ppos != 0) { wil_err(wil, "Offset [%d]\n", (int)*ppos); return -EINVAL; } if (count > sizeof(buf)) { wil_err(wil, "Input too long, len = %d\n", (int)count); return -EINVAL; } rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); if (rc < 0) return rc; buf[rc] = '\0'; if (0 == strcmp(buf, run_command)) wil_set_recovery_state(wil, fw_recovery_running); else wil_err(wil, "Bad recovery command \"%s\"\n", buf); return rc; } static const struct file_operations fops_recovery = { .read = wil_read_file_recovery, .write = wil_write_file_recovery, .open = simple_open, }; /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { Loading Loading @@ -1148,6 +1213,7 @@ static const struct { {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, {"info", S_IRUGO, &fops_info}, {"recovery", S_IRUGO | S_IWUSR, &fops_recovery}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, Loading Loading @@ -1190,6 +1256,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), {}, }; Loading
drivers/net/wireless/ath/wil6210/main.c +38 −8 Original line number Diff line number Diff line Loading @@ -25,9 +25,9 @@ #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 static bool no_fw_recovery; bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); Loading Loading @@ -191,17 +191,38 @@ static void wil_scan_timer_fn(ulong x) schedule_work(&wil->fw_error_worker); } static int wil_wait_for_recovery(struct wil6210_priv *wil) { if (wait_event_interruptible(wil->wq, wil->recovery_state != fw_recovery_pending)) { wil_err(wil, "Interrupt, canceling recovery\n"); return -ERESTARTSYS; } if (wil->recovery_state != fw_recovery_running) { wil_info(wil, "Recovery cancelled\n"); return -EINTR; } wil_info(wil, "Proceed with recovery\n"); return 0; } void wil_set_recovery_state(struct wil6210_priv *wil, int state) { wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__, wil->recovery_state, state); wil->recovery_state = state; wake_up_interruptible(&wil->wq); } static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wireless_dev *wdev = wil->wdev; wil_dbg_misc(wil, "fw error worker\n"); if (no_fw_recovery) return; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ Loading @@ -224,8 +245,13 @@ static void wil_fw_error_worker(struct work_struct *work) case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_MONITOR: wil_info(wil, "fw error recovery started (try %d)...\n", wil_info(wil, "fw error recovery requested (try %d)...\n", wil->recovery_count); if (!no_fw_recovery) wil->recovery_state = fw_recovery_running; if (0 != wil_wait_for_recovery(wil)) break; __wil_down(wil); __wil_up(wil); break; Loading Loading @@ -302,6 +328,7 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); if (!wil->wmi_wq) Loading Loading @@ -331,6 +358,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) { wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); del_timer_sync(&wil->scan_timer); cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); Loading Loading @@ -573,6 +601,7 @@ int wil_reset(struct wil6210_priv *wil) void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); wil->recovery_state = fw_recovery_pending; schedule_work(&wil->fw_error_worker); } Loading Loading @@ -724,6 +753,7 @@ int wil_down(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); rc = __wil_down(wil); mutex_unlock(&wil->mutex); Loading
drivers/net/wireless/ath/wil6210/wil6210.h +11 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/timex.h> #include "wil_platform.h" extern bool no_fw_recovery; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" Loading Loading @@ -379,6 +380,12 @@ struct wil_sta_info { unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; }; enum { fw_recovery_idle = 0, fw_recovery_pending = 1, fw_recovery_running = 2, }; struct wil6210_priv { struct pci_dev *pdev; int n_msi; Loading @@ -389,8 +396,10 @@ struct wil6210_priv { u32 hw_version; struct wil_board *board; u8 n_mids; /* number of additional MIDs as reported by FW */ int recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_state; /* FW recovery state machine */ unsigned long last_fw_recovery; /* jiffies of last fw recovery */ wait_queue_head_t wq; /* for all wait_event() use */ /* profile */ u32 monitor_flags; u32 secure_pcp; /* create secure PCP? */ Loading Loading @@ -507,6 +516,7 @@ void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); void wil_set_itr_trsh(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); Loading
drivers/net/wireless/ath/wil6210/wmi.c +1 −0 Original line number Diff line number Diff line Loading @@ -299,6 +299,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, { wil_dbg_wmi(wil, "WMI: got FW ready event\n"); wil_set_recovery_state(wil, fw_recovery_idle); set_bit(wil_status_fwready, &wil->status); /* let the reset sequence continue */ complete(&wil->wmi_ready); Loading