Re: [ath9k-devel] [PATCH 0/6] ath10k: fixes
Michal Kazior writes: > This includes 2 patches from my previous patchset > that had conflicts. It is now rebased and should > apply cleanly on the github master branch. > > Michal Kazior (6): > ath10k: embed HTC struct inside ath10k > ath10k: embed HTT struct inside ath10k > ath10k: improve locking > ath10k: abort scan properly if wmi_scan_stop fails > ath10k: wait for CE to drain when shutting down > ath10k: add missing debug prints Patches 1 and 2 applied, will review patches 3-6 later. Please don't added new unrelated patches to the patchset while in review. It just confuses everyone, especially me. -- Kalle Valo ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 2/3] ath10k: implement fw crash simulation command
This can be useful to test FW crash handling. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/wmi.c | 19 +++ drivers/net/wireless/ath/ath10k/wmi.h | 19 +++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0d25cd7..5e42460 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2092,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID); } + +int ath10k_wmi_force_fw_hang(struct ath10k *ar, +enum wmi_force_fw_hang_type type, u32 delay_ms) +{ + struct wmi_force_fw_hang_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_force_fw_hang_cmd *)skb->data; + cmd->type = __cpu_to_le32(type); + cmd->delay_ms = __cpu_to_le32(delay_ms); + + ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", + type, delay_ms); + return ath10k_wmi_cmd_send(ar, skb, WMI_FORCE_FW_HANG_CMDID); +} diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9555f5a..da3b2bc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -416,6 +416,7 @@ enum wmi_cmd_id { WMI_PDEV_FTM_INTG_CMDID, WMI_VDEV_SET_KEEPALIVE_CMDID, WMI_VDEV_GET_KEEPALIVE_CMDID, + WMI_FORCE_FW_HANG_CMDID, /* GPIO Configuration */ WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO), @@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd { struct wmi_sta_keepalive_arp_resp arp_resp; } __packed; +enum wmi_force_fw_hang_type { + WMI_FORCE_FW_HANG_ASSERT = 1, + WMI_FORCE_FW_HANG_NO_DETECT, + WMI_FORCE_FW_HANG_CTRL_EP_FULL, + WMI_FORCE_FW_HANG_EMPTY_POINT, + WMI_FORCE_FW_HANG_STACK_OVERFLOW, + WMI_FORCE_FW_HANG_INFINITE_LOOP, +}; + +#define WMI_FORCE_FW_HANG_RANDOM_TIME 0x + +struct wmi_force_fw_hang_cmd { + __le32 type; + __le32 delay_ms; +} __packed; + #define ATH10K_RTS_MAX 2347 #define ATH10K_FRAGMT_THRESHOLD_MIN540 #define ATH10K_FRAGMT_THRESHOLD_MAX2346 @@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg); int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, const struct wmi_pdev_set_wmm_params_arg *arg); int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); +int ath10k_wmi_force_fw_hang(struct ath10k *ar, +enum wmi_force_fw_hang_type type, u32 delay_ms); #endif /* _WMI_H_ */ -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 1/3] ath10k: implement device recovery
Restart the hardware if FW crashes. If FW crashes during recovery we leave the hardware in a "wedged" state to avoid recursive recoveries. When in "wedged" state userspace may bring interfaces down (to issue stop()) and then bring one interface (to issue start()) to reload hardware manually. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 30 ++ drivers/net/wireless/ath/ath10k/core.h |3 +++ drivers/net/wireless/ath/ath10k/htc.c |3 +++ drivers/net/wireless/ath/ath10k/mac.c | 32 ++-- drivers/net/wireless/ath/ath10k/pci.c |2 ++ drivers/net/wireless/ath/ath10k/wmi.c |7 +++ 6 files changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 94230fb..9188fb7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -476,6 +476,34 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } +static void ath10k_core_restart(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, restart_work); + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); + + if (ar->state == ATH10K_STATE_RESTARTING) { + ath10k_err("crashed while restarting. will not attempt to restart the device anymore\n"); + ar->state = ATH10K_STATE_WEDGED; + goto skip; + } + + ath10k_info("attempting to restart the device\n"); + ar->state = ATH10K_STATE_RESTARTING; + + if (ar->scan.in_progress) { + del_timer(&ar->scan.timeout); + ar->scan.in_progress = false; + ieee80211_scan_completed(ar->hw, true); + } + ieee80211_restart_hw(ar->hw); + +skip: + spin_unlock_bh(&ar->data_lock); + mutex_unlock(&ar->conf_mutex); +} + struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, const struct ath10k_hif_ops *hif_ops) { @@ -519,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_waitqueue_head(&ar->event_queue); + INIT_WORK(&ar->restart_work, ath10k_core_restart); + return ar; err_wq: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index ed672f3..ef233c0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -250,6 +250,7 @@ struct ath10k_debug { enum ath10k_state { ATH10K_STATE_OFF = 0, ATH10K_STATE_RESTARTING, + ATH10K_STATE_WEDGED, ATH10K_STATE_ON }; @@ -356,6 +357,8 @@ struct ath10k { enum ath10k_state state; + struct work_struct restart_work; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 7d5a366..72e072c 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -246,6 +246,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, { struct ath10k_htc_ep *ep = &htc->endpoint[eid]; + if (htc->ar->state == ATH10K_STATE_WEDGED) + return -ECOMM; + if (eid >= ATH10K_HTC_EP_COUNT) { ath10k_warn("Invalid endpoint id: %d\n", eid); return -ENOENT; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c64e7be..6c97319 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1806,6 +1806,7 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_unlock(&ar->conf_mutex); cancel_work_sync(&ar->offchan_tx_work); + cancel_work_sync(&ar->restart_work); } static void ath10k_config_ps(struct ath10k *ar) @@ -2793,6 +2794,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) { struct ath10k *ar = hw->priv; + bool skip; int ret; /* mac80211 doesn't care if we really xmit queued frames or not @@ -2802,17 +2804,26 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) mutex_lock(&ar->conf_mutex); + if (ar->state == ATH10K_STATE_WEDGED) + goto skip; + ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; + spin_lock_bh(&ar->htt.tx_lock); empty = bitmap_empty(ar->htt.used_msdu_ids, ar->htt.max_num_pending_tx); spin_unlock_bh(&ar->htt.tx_lock); - (empty); + + skip = (ar->state == ATH10K_STATE_WEDGED); + + (empty || skip); }), ATH
[ath9k-devel] [PATCH 0/3] ath10k: hardware recovery
There's one issue I've noticed. When associated to WPA network tx is discarded by the firmware after recovery (no idea why, yet). This can be fixed in a follow up patch perhaps. Note: this is not based on master branch. It is based on my latest 'ath10k: fixes' and 'ath10k: device setup refactor'. Split for easier review. Michal Kazior (3): ath10k: implement device recovery ath10k: implement fw crash simulation command ath10k: create debugfs interface to trigger fw crash drivers/net/wireless/ath/ath10k/core.c | 30 drivers/net/wireless/ath/ath10k/core.h |3 +++ drivers/net/wireless/ath/ath10k/debug.c | 39 +++ drivers/net/wireless/ath/ath10k/htc.c |3 +++ drivers/net/wireless/ath/ath10k/mac.c | 32 +++-- drivers/net/wireless/ath/ath10k/pci.c |2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 26 + drivers/net/wireless/ath/ath10k/wmi.h | 19 +++ 8 files changed, 152 insertions(+), 2 deletions(-) -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 3/3] ath10k: create debugfs interface to trigger fw crash
This can be useful for testing. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/debug.c | 39 +++ 1 file changed, 39 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 499034b..7ab7f1e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -443,6 +443,42 @@ static const struct file_operations fops_fw_stats = { .llseek = default_llseek, }; +static ssize_t ath10k_read_simulate_fw_crash(struct file *file, +char __user *user_buf, +size_t count, loff_t *ppos) +{ + const char buf[] = "To simulate firmware crash write anything to this" + " file.\nThis will force firmware to report a crash" + " to the host system.\n"; + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); +} + +static ssize_t ath10k_write_simulate_fw_crash(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + int ret; + + ath10k_info("simulating firmware crash\n"); + + mutex_lock(&ar->conf_mutex); + ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); + if (ret) + ath10k_warn("failed to force fw hang (%d)\n", ret); + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_simulate_fw_crash = { + .read = ath10k_read_simulate_fw_crash, + .write = ath10k_write_simulate_fw_crash, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.debugfs_phy = debugfs_create_dir("ath10k", @@ -459,6 +495,9 @@ int ath10k_debug_create(struct ath10k *ar) debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_wmi_services); + debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_simulate_fw_crash); + return 0; } #endif /* CONFIG_ATH10K_DEBUGFS */ -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 09/10] ath10k: skip updating some params during resume
ath10k handles some hw configuration per-vdev (i.e. per-vif). When resuming/restarting hw configuration vdevs may not be re-added yet. Setting vdev params for non existent vdevs crashes the firmware. The parameters are updated when interface is re-added. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/mac.c | 55 - 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ebdaf1a..c64e7be 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1808,13 +1808,35 @@ static void ath10k_stop(struct ieee80211_hw *hw) cancel_work_sync(&ar->offchan_tx_work); } -static int ath10k_config(struct ieee80211_hw *hw, u32 changed) +static void ath10k_config_ps(struct ath10k *ar) { struct ath10k_generic_iter ar_iter; + + lockdep_assert_held(&ar->conf_mutex); + + /* During HW reconfiguration mac80211 reports all interfaces that were +* running until reconfiguration was started. Since FW doesn't have any +* vdevs at this point we must not iterate over this interface list. +* This setting will be updated upon add_interface(). */ + if (ar->state == ATH10K_STATE_RESTARTING) + return; + + memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); + ar_iter.ar = ar; + + ieee80211_iterate_active_interfaces_atomic( + ar->hw, IEEE80211_IFACE_ITER_NORMAL, + ath10k_ps_iter, &ar_iter); + + if (ar_iter.ret) + ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret); +} + +static int ath10k_config(struct ieee80211_hw *hw, u32 changed) +{ struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; int ret = 0; - u32 flags; mutex_lock(&ar->conf_mutex); @@ -1826,18 +1848,8 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&ar->data_lock); } - if (changed & IEEE80211_CONF_CHANGE_PS) { - memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter)); - ar_iter.ar = ar; - flags = IEEE80211_IFACE_ITER_RESUME_ALL; - - ieee80211_iterate_active_interfaces_atomic(hw, - flags, - ath10k_ps_iter, - &ar_iter); - - ret = ar_iter.ret; - } + if (changed & IEEE80211_CONF_CHANGE_PS) + ath10k_config_ps(ar); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (conf->flags & IEEE80211_CONF_MONITOR) @@ -1846,6 +1858,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) ret = ath10k_monitor_destroy(ar); } + ath10k_wmi_flush_tx(ar); mutex_unlock(&ar->conf_mutex); return ret; } @@ -2688,6 +2701,13 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif) lockdep_assert_held(&arvif->ar->conf_mutex); + /* During HW reconfiguration mac80211 reports all interfaces that were +* running until reconfiguration was started. Since FW doesn't have any +* vdevs at this point we must not iterate over this interface list. +* This setting will be updated upon add_interface(). */ + if (ar_iter->ar->state == ATH10K_STATE_RESTARTING) + return; + rts = min_t(u32, rts, ATH10K_RTS_MAX); ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id, @@ -2728,6 +2748,13 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif) lockdep_assert_held(&arvif->ar->conf_mutex); + /* During HW reconfiguration mac80211 reports all interfaces that were +* running until reconfiguration was started. Since FW doesn't have any +* vdevs at this point we must not iterate over this interface list. +* This setting will be updated upon add_interface(). */ + if (ar_iter->ar->state == ATH10K_STATE_RESTARTING) + return; + frag = clamp_t(u32, frag, ATH10K_FRAGMT_THRESHOLD_MIN, ATH10K_FRAGMT_THRESHOLD_MAX); -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 10/10] ath10k: store firmware files in memory
Different FW versions may provide different functions thus mean different hw capabilities advertised to mac80211. It is safe to swap firmware files on disk during driver/device runtime without worries. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 157 +--- drivers/net/wireless/ath/ath10k/core.h |4 + 2 files changed, 109 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 97bf27a..94230fb 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, static int ath10k_download_board_data(struct ath10k *ar) { + const struct firmware *fw = ar->board_data; u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 address; - const struct firmware *fw; int ret; - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.board); - if (IS_ERR(fw)) { - ath10k_err("could not fetch board data fw file (%ld)\n", - PTR_ERR(fw)); - return PTR_ERR(fw); - } - ret = ath10k_push_board_ext_data(ar, fw); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); @@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar) } exit: - release_firmware(fw); return ret; } static int ath10k_download_and_run_otp(struct ath10k *ar) { - const struct firmware *fw; - u32 address; + const struct firmware *fw = ar->otp; + u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ - if (ar->hw_params.fw.otp == NULL) { - ath10k_info("otp file not defined\n"); - return 0; - } - - address = ar->hw_params.patch_load_addr; - - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.otp); - if (IS_ERR(fw)) { - ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw)); + if (!ar->otp) return 0; - } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { @@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) } exit: - release_firmware(fw); return ret; } static int ath10k_download_fw(struct ath10k *ar) { - const struct firmware *fw; + const struct firmware *fw = ar->firmware; u32 address; int ret; - if (ar->hw_params.fw.fw == NULL) - return -EINVAL; - address = ar->hw_params.patch_load_addr; - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.fw); - if (IS_ERR(fw)) { - ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw)); - return PTR_ERR(fw); - } - ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { ath10k_err("could not write fw (%d)\n", ret); @@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar) } exit: - release_firmware(fw); + return ret; +} + +static void ath10k_core_free_firmware_files(struct ath10k *ar) +{ + if (ar->board_data && !IS_ERR(ar->board_data)) + release_firmware(ar->board_data); + + if (ar->otp && !IS_ERR(ar->otp)) + release_firmware(ar->otp); + + if (ar->firmware && !IS_ERR(ar->firmware)) + release_firmware(ar->firmware); + + ar->board_data = NULL; + ar->otp = NULL; + ar->firmware = NULL; +} + +static int ath10k_core_fetch_firmware_files(struct ath10k *ar) +{ + int ret = 0; + + if (ar->hw_params.fw.fw == NULL) { + ath10k_err("firmware file not defined\n"); + return -EINVAL; + } + + if (ar->hw_params.fw.board == NULL) { + ath10k_err("board data file not defined"); + return -EINVAL; + } + + ar->board_data = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + if (IS_ERR(ar->board_data)) { + ret = PTR_ERR(ar->board_data); + ath10k_err("could not fetch board data (%d)\n", ret); + goto err; + } + + ar->firmware = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.fw); + if (IS_ERR(ar->firmware)) { + ret = PTR_ERR(ar->firmware); + ath10k_err("could not fetch firmware (%d)\n", ret); + goto err; +
[ath9k-devel] [PATCH v2 08/10] ath10k: defer hw setup to start/stop mac80211 hooks
This fixes suspend-to-disk. The hardware is now re-initialized upon freeze/thaw properly. This also makes suspend/resume re-initialize the hardware as WoWLAN support is not done yet. With some little work it should be possible to support hw reconfiguration for hw/fw recovery. HW must be initialized once before registering to mac80211 because FW determinates what hw capabilities can be advertised. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 46 +--- drivers/net/wireless/ath/ath10k/core.h |1 + drivers/net/wireless/ath/ath10k/mac.c | 45 +++ drivers/net/wireless/ath/ath10k/pci.c | 10 +-- 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 0e4a704..97bf27a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -601,6 +601,7 @@ err_wmi_detach: err: return status; } +EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_stop(struct ath10k *ar) { @@ -608,18 +609,49 @@ void ath10k_core_stop(struct ath10k *ar) ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); } +EXPORT_SYMBOL(ath10k_core_stop); + +/* mac80211 manages fw/hw initialization through start/stop hooks. However in + * order to know what hw capabilities should be advertised to mac80211 it is + * necessary to load the firmware (and tear it down immediately since start + * hook will try to init it again) before registering */ +static int ath10k_core_probe_fw(struct ath10k *ar) +{ + int ret; + + ret = ath10k_hif_init(ar); + if (ret) { + ath10k_err("could not start pci hif (%d)\n", ret); + return ret; + } + + ret = ath10k_core_start(ar); + if (ret) { + ath10k_err("could not init core (%d)\n", ret); + ath10k_hif_deinit(ar); + return ret; + } + + ath10k_core_stop(ar); + ath10k_hif_deinit(ar); + return 0; +} int ath10k_core_register(struct ath10k *ar) { int status; - status = ath10k_core_start(ar); - if (status) - goto err; + status = ath10k_core_probe_fw(ar); + if (status) { + ath10k_err("could not probe fw (%d)\n", status); + return status; + } status = ath10k_mac_register(ar); - if (status) - goto err_core_stop; + if (status) { + ath10k_err("could not register to mac80211 (%d)\n", status); + return status; + } status = ath10k_debug_create(ar); if (status) { @@ -631,9 +663,6 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); -err_core_stop: - ath10k_core_stop(ar); -err: return status; } EXPORT_SYMBOL(ath10k_core_register); @@ -644,7 +673,6 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_core_stop(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index eca723b..5224a84 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -249,6 +249,7 @@ struct ath10k_debug { enum ath10k_state { ATH10K_STATE_OFF = 0, + ATH10K_STATE_RESTARTING, ATH10K_STATE_ON }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a49a8bf..ebdaf1a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1735,13 +1735,50 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* * Initialize various parameters with default vaules. */ +static void ath10k_halt(struct ath10k *ar) +{ + if (ar->state == ATH10K_STATE_OFF) + return; + + del_timer_sync(&ar->scan.timeout); + ath10k_offchan_tx_purge(ar); + ath10k_peer_cleanup_all(ar); + ath10k_core_stop(ar); + ath10k_hif_deinit(ar); +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; - int ret; + int ret = 0; mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_OFF) { + /* This can be called in case if resume fails or +* ieee80211_hw_restart() was issued */ + ath10k_info("hw reconfiguration started\n"); + ath10k_halt(ar); + ar->state = ATH10K_STATE_RESTARTING; + } else { + ar->state = ATH10K_STATE_ON; + } + + ret = ath10k_hif_init(ar); + if (ret) { + ath10k_err("could not init hif (%d)\n", ret); + ar->state = ATH10K_STA
[ath9k-devel] [PATCH v2 07/10] ath10k: make sure all resources are freed upon ath10k_stop()
This is necessary for proper hw reconfiguration and to avoid memory leaks. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/mac.c | 16 1 file changed, 16 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 23e48ca5..a49a8bf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -366,6 +366,20 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) spin_unlock_bh(&ar->data_lock); } +static void ath10k_peer_cleanup_all(struct ath10k *ar) +{ + struct ath10k_peer *peer, *tmp; + + lockdep_assert_held(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(peer, tmp, &ar->peers, list) { + list_del(&peer->list); + kfree(peer); + } + spin_unlock_bh(&ar->data_lock); +} + // /* Interface management */ // @@ -1750,7 +1764,9 @@ static void ath10k_stop(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); + del_timer_sync(&ar->scan.timeout); ath10k_offchan_tx_purge(ar); + ath10k_peer_cleanup_all(ar); ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 04/10] ath10k: reset BMI state upon init
This is necessary if we want to be able to restart hw on-the-fly. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/bmi.c |6 ++ drivers/net/wireless/ath/ath10k/bmi.h |1 + drivers/net/wireless/ath/ath10k/core.c |2 ++ 3 files changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index aeae029..744da6d 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -20,6 +20,12 @@ #include "debug.h" #include "htc.h" +void ath10k_bmi_start(struct ath10k *ar) +{ + ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n"); + ar->bmi.done_sent = false; +} + int ath10k_bmi_done(struct ath10k *ar) { struct bmi_cmd cmd; diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 32c56aa..8d81ce1 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -184,6 +184,7 @@ struct bmi_target_info { #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 +void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dcddae4..3d75c6a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -507,6 +507,8 @@ int ath10k_core_start(struct ath10k *ar) struct bmi_target_info target_info; int status; + ath10k_bmi_start(ar); + memset(&target_info, 0, sizeof(target_info)); status = ath10k_bmi_get_target_info(ar, &target_info); if (status) -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 05/10] ath10k: decouple suspend code
Split up fw-related and hw-related suspension code. Although we don't advertise WoW support to mac80211 yet it's useful to keep the code in suspend/resume hooks. At this point there's no need to keep pci pm ops. In case of WoW mac80211 calls ath10k_suspend() which should take care of entering low-power mode. In case WoW is not available mac80211 will go through regular interface teradown and use start/stop. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 28 - drivers/net/wireless/ath/ath10k/core.h |3 - drivers/net/wireless/ath/ath10k/hif.h | 19 drivers/net/wireless/ath/ath10k/mac.c | 66 drivers/net/wireless/ath/ath10k/pci.c | 176 ++-- 5 files changed, 138 insertions(+), 154 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3d75c6a..01c1d82 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -648,34 +648,6 @@ void ath10k_core_unregister(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_unregister); -int ath10k_core_target_suspend(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); - - ret = ath10k_wmi_pdev_suspend_target(ar); - if (ret) - ath10k_warn("could not suspend target (%d)\n", ret); - - return ret; -} -EXPORT_SYMBOL(ath10k_core_target_suspend); - -int ath10k_core_target_resume(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); - - ret = ath10k_wmi_pdev_resume_target(ar); - if (ret) - ath10k_warn("could not resume target (%d)\n", ret); - - return ret; -} -EXPORT_SYMBOL(ath10k_core_target_resume); - MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 844b160..eca723b 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -365,7 +365,4 @@ void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); -int ath10k_core_target_suspend(struct ath10k *ar); -int ath10k_core_target_resume(struct ath10k *ar); - #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 3a257d1..00bfb03 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -80,6 +80,9 @@ struct ath10k_hif_ops { /* Power down the device and free up resources. stop() must be called * before this if start() was called earlier */ void (*deinit)(struct ath10k *ar); + + int (*suspend)(struct ath10k *ar); + int (*resume)(struct ath10k *ar); }; @@ -154,4 +157,20 @@ static inline void ath10k_hif_deinit(struct ath10k *ar) ar->hif.ops->deinit(ar); } +static inline int ath10k_hif_suspend(struct ath10k *ar) +{ + if (!ar->hif.ops->suspend) + return -EOPNOTSUPP; + + return ar->hif.ops->suspend(ar); +} + +static inline int ath10k_hif_resume(struct ath10k *ar) +{ + if (!ar->hif.ops->resume) + return -EOPNOTSUPP; + + return ar->hif.ops->resume(ar); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f34ddb2..23e48ca5 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -20,6 +20,7 @@ #include #include +#include "hif.h" #include "core.h" #include "debug.h" #include "wmi.h" @@ -2746,6 +2747,67 @@ static int ath10k_tx_last_beacon(struct ieee80211_hw *hw) return 1; } +#ifdef CONFIG_PM +static int ath10k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct ath10k *ar = hw->priv; + int ret; + + ar->is_target_paused = false; + + ret = ath10k_wmi_pdev_suspend_target(ar); + if (ret) { + ath10k_warn("could not suspend target (%d)\n", ret); + return 1; + } + + ret = wait_event_interruptible_timeout(ar->event_queue, + ar->is_target_paused == true, + 1 * HZ); + if (ret < 0) { + ath10k_warn("suspend interrupted (%d)\n", ret); + goto resume; + } else if (ret == 0) { + ath10k_warn("suspend timed out - target pause event never came\n"); + goto resume; + } + + ret = ath10k_hif_suspend(ar); + if (ret) { + ath10k_warn("could not suspend hif (%d)\n", ret); + goto resume; + } + + return 0; +resume: + ret = ath10k_wmi_pdev_resume_target(ar);
[ath9k-devel] [PATCH v2 06/10] ath10k: move free_vdev_map initialization
This is necessary for hw reconfiguration to work. Since mac80211 is not calling remove_interface() is such case we must reset free_vdev_map. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 01c1d82..0e4a704 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -458,8 +458,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; - ar->free_vdev_map = 0xFF; /* 8 vdevs */ - init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); @@ -590,6 +588,8 @@ int ath10k_core_start(struct ath10k *ar) if (status) goto err_disconnect_htc; + ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; + return 0; err_disconnect_htc: -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 03/10] ath10k: allow deferred regd update
Regulatory domain notification hook can be called regardless of the hw state (i.e. before start mac80211 callback). Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.h |7 +++ drivers/net/wireless/ath/ath10k/mac.c | 26 +++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 5a0b2ce..844b160 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -247,6 +247,11 @@ struct ath10k_debug { struct completion event_stats_compl; }; +enum ath10k_state { + ATH10K_STATE_OFF = 0, + ATH10K_STATE_ON +}; + struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; @@ -344,6 +349,8 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; + enum ath10k_state state; + #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4867f30..f34ddb2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1307,23 +1307,19 @@ static int ath10k_update_channel_list(struct ath10k *ar) return ret; } -static void ath10k_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +static void ath10k_regd_update(struct ath10k *ar) { - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct reg_dmn_pair_mapping *regpair; - struct ath10k *ar = hw->priv; int ret; - mutex_lock(&ar->conf_mutex); - - ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + lockdep_assert_held(&ar->conf_mutex); ret = ath10k_update_channel_list(ar); if (ret) ath10k_warn("could not update channel list (%d)\n", ret); regpair = ar->ath_common.regulatory.regpair; + /* Target allows setting up per-band regdomain but ath_common provides * a combined one only */ ret = ath10k_wmi_pdev_set_regdomain(ar, @@ -1334,7 +1330,19 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, regpair->reg_5ghz_ctl); if (ret) ath10k_warn("could not set pdev regdomain (%d)\n", ret); +} +static void ath10k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath10k *ar = hw->priv; + + ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); + + mutex_lock(&ar->conf_mutex); + if (ar->state == ATH10K_STATE_ON) + ath10k_regd_update(ar); mutex_unlock(&ar->conf_mutex); } @@ -1729,6 +1737,9 @@ static int ath10k_start(struct ieee80211_hw *hw) ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n", ret); + ar->state = ATH10K_STATE_ON; + ath10k_regd_update(ar); + mutex_unlock(&ar->conf_mutex); return 0; } @@ -1739,6 +1750,7 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); ath10k_offchan_tx_purge(ar); + ar->state = ATH10K_STATE_OFF; mutex_unlock(&ar->conf_mutex); cancel_work_sync(&ar->offchan_tx_work); -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 00/10] ath10k: device setup refactor
This is a respin of my patchset that addresses hibernation issues. This is also groundwork for proper hw recovery that I'm going to post soon. I addressed review comments and some bugs I've found along. Note: this is not based on master branch but on my latest 'ath10k: fixes' patches. Split for easier review. Michal Kazior (10): ath10k: decouple pci init/deinit logic ath10k: decouple core start/stop logic ath10k: allow deferred regd update ath10k: reset BMI state upon init ath10k: decouple suspend code ath10k: move free_vdev_map initialization ath10k: make sure all resources are freed upon ath10k_stop() ath10k: defer hw setup to start/stop mac80211 hooks ath10k: skip updating some params during resume ath10k: store firmware files in memory drivers/net/wireless/ath/ath10k/bmi.c |6 + drivers/net/wireless/ath/ath10k/bmi.h |1 + drivers/net/wireless/ath/ath10k/core.c | 249 ++-- drivers/net/wireless/ath/ath10k/core.h | 17 +- drivers/net/wireless/ath/ath10k/hif.h | 39 + drivers/net/wireless/ath/ath10k/mac.c | 202 --- drivers/net/wireless/ath/ath10k/pci.c | 284 +--- 7 files changed, 520 insertions(+), 278 deletions(-) -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 02/10] ath10k: decouple core start/stop logic
Enables code reuse for proper hw reconfiguration that is in turn required for proper suspend/hibernation/wowlan support. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 44 +++- drivers/net/wireless/ath/ath10k/core.h |2 ++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f1312fa..dcddae4 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -502,8 +502,7 @@ void ath10k_core_destroy(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_destroy); - -int ath10k_core_register(struct ath10k *ar) +int ath10k_core_start(struct ath10k *ar) { struct bmi_target_info target_info; int status; @@ -589,9 +588,36 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err_disconnect_htc; + return 0; + +err_disconnect_htc: + ath10k_htc_stop(&ar->htc); +err_htt_detach: + ath10k_htt_detach(&ar->htt); +err_wmi_detach: + ath10k_wmi_detach(ar); +err: + return status; +} + +void ath10k_core_stop(struct ath10k *ar) +{ + ath10k_htc_stop(&ar->htc); + ath10k_htt_detach(&ar->htt); + ath10k_wmi_detach(ar); +} + +int ath10k_core_register(struct ath10k *ar) +{ + int status; + + status = ath10k_core_start(ar); + if (status) + goto err; + status = ath10k_mac_register(ar); if (status) - goto err_disconnect_htc; + goto err_core_stop; status = ath10k_debug_create(ar); if (status) { @@ -603,12 +629,8 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); -err_disconnect_htc: - ath10k_htc_stop(&ar->htc); -err_htt_detach: - ath10k_htt_detach(&ar->htt); -err_wmi_detach: - ath10k_wmi_detach(ar); +err_core_stop: + ath10k_core_stop(ar); err: return status; } @@ -620,9 +642,7 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_htc_stop(&ar->htc); - ath10k_htt_detach(&ar->htt); - ath10k_wmi_detach(ar); + ath10k_core_stop(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2f7065c..5a0b2ce 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -353,6 +353,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); +int ath10k_core_start(struct ath10k *ar); +void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 01/10] ath10k: decouple pci init/deinit logic
Split logic that prepares the device for BMI phase/cleans up related resources. This is necessary for ath10k to be able to restart hw on the fly without reloading the module. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/hif.h | 20 ++ drivers/net/wireless/ath/ath10k/pci.c | 110 + 2 files changed, 91 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 010e265..3a257d1 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -46,8 +46,11 @@ struct ath10k_hif_ops { void *request, u32 request_len, void *response, u32 *response_len); + /* Post BMI phase, after FW is loaded. Starts regular operation */ int (*start)(struct ath10k *ar); + /* Clean up what start() did. This does not revert to BMI phase. If +* desired so, call deinit() and init() */ void (*stop)(struct ath10k *ar); int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, @@ -70,6 +73,13 @@ struct ath10k_hif_ops { struct ath10k_hif_cb *callbacks); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); + + /* Power up the device and enter BMI transfer mode for FW download */ + int (*init)(struct ath10k *ar); + + /* Power down the device and free up resources. stop() must be called +* before this if start() was called earlier */ + void (*deinit)(struct ath10k *ar); }; @@ -134,4 +144,14 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, return ar->hif.ops->get_free_queue_number(ar, pipe_id); } +static inline int ath10k_hif_init(struct ath10k *ar) +{ + return ar->hif.ops->init(ar); +} + +static inline void ath10k_hif_deinit(struct ath10k *ar) +{ + ar->hif.ops->deinit(ar); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 06124a4..97f80e5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); +static void ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_reset_target(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* host->target HTC control and raw streams */ @@ -1755,6 +1757,66 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } +static int ath10k_pci_hif_init(struct ath10k *ar) +{ + int ret; + + /* +* Bring the target up cleanly. +* +* The target may be in an undefined state with an AUX-powered Target +* and a Host in WoW mode. If the Host crashes, loses power, or is +* restarted (without unloading the driver) then the Target is left +* (aux) powered and running. On a subsequent driver load, the Target +* is in an unexpected state. We try to catch that here in order to +* reset the Target and retry the probe. +*/ + ath10k_pci_device_reset(ar); + + ret = ath10k_pci_reset_target(ar); + if (ret) + goto err; + + if (ath10k_target_ps) { + ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save enabled\n"); + } else { + /* Force AWAKE forever */ + ath10k_dbg(ATH10K_DBG_PCI, "on-chip power save disabled\n"); + ath10k_do_pci_wake(ar); + } + + ret = ath10k_pci_ce_init(ar); + if (ret) + goto err_ps; + + ret = ath10k_pci_init_config(ar); + if (ret) + goto err_ce; + + ret = ath10k_pci_wake_target_cpu(ar); + if (ret) { + ath10k_err("could not wake up target CPU (%d)\n", ret); + goto err_ce; + } + + return 0; + +err_ce: + ath10k_pci_ce_deinit(ar); +err_ps: + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +err: + return ret; +} + +static void ath10k_pci_hif_deinit(struct ath10k *ar) +{ + ath10k_pci_ce_deinit(ar); + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +} + static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_head = ath10k_pci_hif_send_head, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, @@ -1765,6 +1827,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_complete_check= ath10k_pci_hif_send_complete_check, .set_callbacks = ath10k_pci_hif_set_callbacks, .get_free_queue_number = ath10k_pci_hif_get_free_que
[ath9k-devel] [PATCH 5/6] ath10k: wait for CE to drain when shutting down
ath10k_pci_process_ce() is used to process completions. Only one thread can do that though. If one thread starts handling completions then the other one (i.e. possibly PCI shutdown) would exit immediatelely and free up memory while completions are being processed leading to corruption. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/pci.c | 21 + drivers/net/wireless/ath/ath10k/pci.h |2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1a59638..06124a4 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -765,6 +765,7 @@ static int ath10k_pci_start_ce(struct ath10k *ar) int i, pipe_num, completions, disable_interrupts; spin_lock_init(&ar_pci->compl_lock); + init_waitqueue_head(&ar_pci->compl_wq); INIT_LIST_HEAD(&ar_pci->compl_process); for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) { @@ -953,9 +954,28 @@ static void ath10k_pci_process_ce(struct ath10k *ar) spin_lock_bh(&ar_pci->compl_lock); ar_pci->compl_processing = false; + wake_up(&ar_pci->compl_wq); spin_unlock_bh(&ar_pci->compl_lock); } +/* This function assumes no new data is going to be submitted/completed. It is + * mainly intended to flush out completions when stopping the device. */ +static void ath10k_pci_wait_for_ce_drain(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int ret; + + ret = wait_event_timeout(ar_pci->compl_wq, ({ + bool processing; + spin_lock_bh(&ar_pci->compl_lock); + processing = ar_pci->compl_processing; + spin_unlock_bh(&ar_pci->compl_lock); + (!processing); + }), 5*HZ); + if (ret == 0) + ath10k_warn("timed out while waiting for completions to be processed\n"); +} + /* TODO - temporary mapping while we have too few CE's */ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, u8 *ul_pipe, @@ -1261,6 +1281,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * everything else up. */ ath10k_pci_process_ce(ar); + ath10k_pci_wait_for_ce_drain(ar); ath10k_pci_cleanup_ce(ar); ath10k_pci_buffer_cleanup(ar); } diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d3a2e6c..0403cea 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -215,8 +215,8 @@ struct ath10k_pci { /* protects compl_processing and compl_process */ spinlock_t compl_lock; - bool compl_processing; + wait_queue_head_t compl_wq; struct hif_ce_pipe_info pipe_info[CE_COUNT_MAX]; -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 2/6] ath10k: embed HTT struct inside ath10k
This reduces number of allocations and simplifies memory managemnt. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 12 ++-- drivers/net/wireless/ath/ath10k/core.h |7 +++ drivers/net/wireless/ath/ath10k/htt.c| 25 + drivers/net/wireless/ath/ath10k/htt.h|3 +-- drivers/net/wireless/ath/ath10k/htt_rx.c |3 ++- drivers/net/wireless/ath/ath10k/htt_tx.c |2 +- drivers/net/wireless/ath/ath10k/mac.c| 16 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 4199560..f1312fa 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -556,9 +556,9 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err_wmi_detach; - ar->htt = ath10k_htt_attach(ar); - if (!ar->htt) { - status = -ENOMEM; + status = ath10k_htt_attach(ar); + if (status) { + ath10k_err("could not attach htt (%d)\n", status); goto err_wmi_detach; } @@ -585,7 +585,7 @@ int ath10k_core_register(struct ath10k *ar) goto err_disconnect_htc; } - status = ath10k_htt_attach_target(ar->htt); + status = ath10k_htt_attach_target(&ar->htt); if (status) goto err_disconnect_htc; @@ -606,7 +606,7 @@ err_unregister_mac: err_disconnect_htc: ath10k_htc_stop(&ar->htc); err_htt_detach: - ath10k_htt_detach(ar->htt); + ath10k_htt_detach(&ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); err: @@ -621,7 +621,7 @@ void ath10k_core_unregister(struct ath10k *ar) * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_htc_stop(&ar->htc); - ath10k_htt_detach(ar->htt); + ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index dfd4fe1..2f7065c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -23,6 +23,7 @@ #include #include +#include "htt.h" #include "htc.h" #include "hw.h" #include "targaddrs.h" @@ -273,15 +274,13 @@ struct ath10k { const struct ath10k_hif_ops *ops; } hif; - struct ath10k_wmi wmi; - wait_queue_head_t event_queue; bool is_target_paused; struct ath10k_bmi bmi; + struct ath10k_wmi wmi; struct ath10k_htc htc; - - struct ath10k_htt *htt; + struct ath10k_htt htt; struct ath10k_hw_params { u32 id; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 2bfb9b4..39342c5 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -16,6 +16,7 @@ */ #include +#include #include "htt.h" #include "core.h" @@ -47,15 +48,11 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt) return 0; } -struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) +int ath10k_htt_attach(struct ath10k *ar) { - struct ath10k_htt *htt; + struct ath10k_htt *htt = &ar->htt; int ret; - htt = kzalloc(sizeof(*htt), GFP_KERNEL); - if (!htt) - return NULL; - htt->ar = ar; htt->max_throughput_mbps = 800; @@ -65,8 +62,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) * since ath10k_htt_rx_attach involves sending a rx ring configure * message to the target. */ - if (ath10k_htt_htc_attach(htt)) + ret = ath10k_htt_htc_attach(htt); + if (ret) { + ath10k_err("could not attach htt htc (%d)\n", ret); goto err_htc_attach; + } ret = ath10k_htt_tx_attach(htt); if (ret) { @@ -74,8 +74,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) goto err_htc_attach; } - if (ath10k_htt_rx_attach(htt)) + ret = ath10k_htt_rx_attach(htt); + if (ret) { + ath10k_err("could not attach htt rx (%d)\n", ret); goto err_rx_attach; + } /* * Prefetch enough data to satisfy target @@ -89,13 +92,12 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar) 8 + /* llc snap */ 2; /* ip4 dscp or ip6 priority */ - return htt; + return 0; err_rx_attach: ath10k_htt_tx_detach(htt); err_htc_attach: - kfree(htt); - return NULL; + return ret; } #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ) @@ -148,5 +150,4 @@ void ath10k_htt_detach(struct ath10k_htt *htt) { ath10k_htt_rx_detach(htt); ath10k_htt_tx_detach(htt); - kfree(htt); } diff --git a/drivers/
[ath9k-devel] [PATCH 6/6] ath10k: add missing debug prints
Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/wmi.c |6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 681e941..b7e7e45 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1748,6 +1748,9 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, if (arg->key_data) memcpy(cmd->key_data, arg->key_data, arg->key_len); + ath10k_dbg(ATH10K_DBG_WMI, + "wmi vdev install key idx %d cipher %d len %d\n", + arg->key_idx, arg->key_cipher, arg->key_len); return ath10k_wmi_cmd_send(ar, skb, WMI_VDEV_INSTALL_KEY_CMDID); } @@ -2011,6 +2014,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, cmd->peer_vht_rates.tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); + ath10k_dbg(ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM\n", + arg->vdev_id, arg->addr); return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID); } -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 3/6] ath10k: improve locking
Add more lockdep asserts and a few conf_mutex locks. It's better to be on the safe side. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/mac.c | 57 +++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 7bc746f..def1e68 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -43,6 +43,8 @@ static int ath10k_send_key(struct ath10k_vif *arvif, .macaddr = macaddr, }; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) arg.key_flags = WMI_KEY_PAIRWISE; else @@ -88,6 +90,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif, struct ath10k *ar = arvif->ar; int ret; + lockdep_assert_held(&ar->conf_mutex); + INIT_COMPLETION(ar->install_key_done); ret = ath10k_send_key(arvif, key, cmd, macaddr); @@ -369,6 +373,8 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) { int ret; + lockdep_assert_held(&ar->conf_mutex); + ret = wait_for_completion_timeout(&ar->vdev_setup_done, ATH10K_VDEV_SETUP_TIMEOUT_HZ); if (ret == 0) @@ -602,6 +608,8 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (!info->enable_beacon) { ath10k_vdev_stop(arvif); return; @@ -628,6 +636,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (!info->ibss_joined) { ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer); if (ret) @@ -677,6 +687,8 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) enum wmi_sta_ps_mode psmode; int ret; + lockdep_assert_held(&arvif->ar->conf_mutex); + if (vif->type != NL80211_IFTYPE_STATION) return; @@ -719,6 +731,8 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, struct ieee80211_bss_conf *bss_conf, struct wmi_peer_assoc_complete_arg *arg) { + lockdep_assert_held(&ar->conf_mutex); + memcpy(arg->addr, sta->addr, ETH_ALEN); arg->vdev_id = arvif->vdev_id; arg->peer_aid = sta->aid; @@ -761,6 +775,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, const u8 *rsnie = NULL; const u8 *wpaie = NULL; + lockdep_assert_held(&ar->conf_mutex); + bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan, info->bssid, NULL, 0, 0, 0); if (bss) { @@ -801,6 +817,8 @@ static void ath10k_peer_assoc_h_rates(struct ath10k *ar, u32 ratemask; int i; + lockdep_assert_held(&ar->conf_mutex); + sband = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band]; ratemask = sta->supp_rates[ar->hw->conf.chandef.chan->band]; rates = sband->bitrates; @@ -824,6 +842,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar, int smps; int i, n; + lockdep_assert_held(&ar->conf_mutex); + if (!ht_cap->ht_supported) return; @@ -902,6 +922,8 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar, u32 uapsd = 0; u32 max_sp = 0; + lockdep_assert_held(&ar->conf_mutex); + if (sta->wme) arg->peer_flags |= WMI_PEER_QOS; @@ -1053,6 +1075,8 @@ static int ath10k_peer_assoc(struct ath10k *ar, { struct wmi_peer_assoc_complete_arg arg; + lockdep_assert_held(&ar->conf_mutex); + memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg)); ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg); @@ -1076,6 +1100,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_sta *ap_sta; int ret; + lockdep_assert_held(&ar->conf_mutex); + rcu_read_lock(); ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); @@ -1116,6 +1142,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret; + lockdep_assert_held(&ar->conf_mutex); + /* * For some reason, calling VDEV-DOWN before VDEV-STOP * makes the FW to send frames via HTT after disassociation. @@ -1149,6 +1177,8 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, { int ret = 0; + lockdep_assert_held(&ar->conf_mutex); + ret = ath10k_peer_assoc(ar, arvif, sta, NULL); if (ret) { ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr);
[ath9k-devel] [PATCH 1/6] ath10k: embed HTC struct inside ath10k
This reduces number of allocations and simplifies memory managemnt. Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/core.c | 28 drivers/net/wireless/ath/ath10k/core.h |2 +- drivers/net/wireless/ath/ath10k/htc.c| 23 +-- drivers/net/wireless/ath/ath10k/htc.h|4 +--- drivers/net/wireless/ath/ath10k/htt.c|2 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 10 +- drivers/net/wireless/ath/ath10k/wmi.c|4 ++-- 7 files changed, 27 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index aabe166..4199560 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) goto conn_fail; /* Start HTC */ - status = ath10k_htc_start(ar->htc); + status = ath10k_htc_start(&ar->htc); if (status) goto conn_fail; @@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) return 0; timeout: - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); conn_fail: return status; } @@ -505,7 +505,6 @@ EXPORT_SYMBOL(ath10k_core_destroy); int ath10k_core_register(struct ath10k *ar) { - struct ath10k_htc_ops htc_ops; struct bmi_target_info target_info; int status; @@ -534,26 +533,26 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err; - htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; + ar->htc.htc_ops.target_send_suspend_complete = + ath10k_send_suspend_complete; - ar->htc = ath10k_htc_create(ar, &htc_ops); - if (IS_ERR(ar->htc)) { - status = PTR_ERR(ar->htc); - ath10k_err("could not create HTC (%d)\n", status); + status = ath10k_htc_init(ar); + if (status) { + ath10k_err("could not init HTC (%d)\n", status); goto err; } status = ath10k_bmi_done(ar); if (status) - goto err_htc_destroy; + goto err; status = ath10k_wmi_attach(ar); if (status) { ath10k_err("WMI attach failed: %d\n", status); - goto err_htc_destroy; + goto err; } - status = ath10k_htc_wait_target(ar->htc); + status = ath10k_htc_wait_target(&ar->htc); if (status) goto err_wmi_detach; @@ -605,13 +604,11 @@ int ath10k_core_register(struct ath10k *ar) err_unregister_mac: ath10k_mac_unregister(ar); err_disconnect_htc: - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); err_htt_detach: ath10k_htt_detach(ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); -err_htc_destroy: - ath10k_htc_destroy(ar->htc); err: return status; } @@ -623,10 +620,9 @@ void ath10k_core_unregister(struct ath10k *ar) * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); - ath10k_htc_stop(ar->htc); + ath10k_htc_stop(&ar->htc); ath10k_htt_detach(ar->htt); ath10k_wmi_detach(ar); - ath10k_htc_destroy(ar->htc); } EXPORT_SYMBOL(ath10k_core_unregister); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 7489770..dfd4fe1 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -279,8 +279,8 @@ struct ath10k { bool is_target_paused; struct ath10k_bmi bmi; + struct ath10k_htc htc; - struct ath10k_htc *htc; struct ath10k_htt *htt; struct ath10k_hw_params { diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f37a6e1..7d5a366 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -265,7 +265,7 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb, unsigned int eid) { - struct ath10k_htc *htc = ar->htc; + struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_ep *ep = &htc->endpoint[eid]; bool stopping; @@ -414,7 +414,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar, u8 pipe_id) { int status = 0; - struct ath10k_htc *htc = ar->htc; + struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_hdr *hdr; struct ath10k_htc_ep *ep; u16 payload_len; @@ -961,22 +961,14 @@ void ath10k_htc_stop(struct ath10k_htc *htc) } /* registered target arrival callback from the HIF layer */ -struct at
[ath9k-devel] [PATCH 4/6] ath10k: abort scan properly if wmi_scan_stop fails
Signed-off-by: Michal Kazior --- drivers/net/wireless/ath/ath10k/mac.c |4 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index def1e68..4867f30 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1587,6 +1587,10 @@ static int ath10k_abort_scan(struct ath10k *ar) ret = ath10k_wmi_stop_scan(ar, &arg); if (ret) { ath10k_warn("could not submit wmi stop scan (%d)\n", ret); + spin_lock_bh(&ar->data_lock); + ar->scan.in_progress = false; + ath10k_offchan_tx_purge(ar); + spin_unlock_bh(&ar->data_lock); return -EIO; } -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH 0/6] ath10k: fixes
This includes 2 patches from my previous patchset that had conflicts. It is now rebased and should apply cleanly on the github master branch. Michal Kazior (6): ath10k: embed HTC struct inside ath10k ath10k: embed HTT struct inside ath10k ath10k: improve locking ath10k: abort scan properly if wmi_scan_stop fails ath10k: wait for CE to drain when shutting down ath10k: add missing debug prints drivers/net/wireless/ath/ath10k/core.c | 40 +++- drivers/net/wireless/ath/ath10k/core.h |9 ++-- drivers/net/wireless/ath/ath10k/htc.c| 23 ++--- drivers/net/wireless/ath/ath10k/htc.h|4 +- drivers/net/wireless/ath/ath10k/htt.c| 27 ++- drivers/net/wireless/ath/ath10k/htt.h|3 +- drivers/net/wireless/ath/ath10k/htt_rx.c |3 +- drivers/net/wireless/ath/ath10k/htt_tx.c | 12 ++--- drivers/net/wireless/ath/ath10k/mac.c| 77 ++ drivers/net/wireless/ath/ath10k/pci.c| 21 drivers/net/wireless/ath/ath10k/pci.h|2 +- drivers/net/wireless/ath/ath10k/wmi.c| 10 +++- 12 files changed, 148 insertions(+), 83 deletions(-) -- 1.7.9.5 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
Re: [ath9k-devel] [PATCH] mac80211: Use RCU protection in ieee80211_get_tx_rates()
On 2013-06-12 10:00 AM, Calvin Owens wrote: > Copying the rate table should be done in an RCU read-side critical > section. I think this approach is wrong. The sta entry is also under RCU protection (no locking for read access in that part of the code. In a normal driver tx path, no extra rcu_read_lock/rcu_read_unlock is needed. Only if the driver does some scheduling outside of the tx function (which ath9k does), this RCU warning appears. How about this change instead: --- --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1570,6 +1570,8 @@ void ath_txq_schedule(struct ath_softc * txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; + rcu_read_lock(); + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); @@ -1608,8 +1610,10 @@ void ath_txq_schedule(struct ath_softc * if (ac == last_ac || txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) - return; + break; } + + rcu_read_unlock(); } /***/ ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH] mac80211: Use RCU protection in ieee80211_get_tx_rates()
Copying the rate table should be done in an RCU read-side critical section. Signed-off-by: Calvin Owens --- net/mac80211/rate.c | 4 1 file changed, 4 insertions(+) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index d3f414f..090d9b0 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -538,6 +538,8 @@ static void rate_control_fill_sta_table(struct ieee80211_sta *sta, struct ieee80211_sta_rates *ratetbl = NULL; int i; + rcu_read_lock(); + if (sta && !info->control.skip_table) ratetbl = rcu_dereference(sta->rates); @@ -566,6 +568,8 @@ static void rate_control_fill_sta_table(struct ieee80211_sta *sta, if (rates[i].idx < 0 || !rates[i].count) break; } + + rcu_read_unlock(); } static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, -- 1.8.2.1 ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
Re: [ath9k-devel] [PATCH] mac80211: ath9k: Use RCU protection calling ieee80211_get_tx_rates
On Tuesday 06/11 at 21:55 +0200, Johannes Berg wrote: > Now the subject should no longer say "mac80211:" :) > > However... given that ieee80211_get_tx_rates() actually *copies* the > rates into the parameter, I guess it should do the rcu_read_lock() > internally. I guess I wasn't paying attention previously. Felix? I thought about that, but it seemed too simple, so I assumed I was missing something. ;) I'll send a patch per above. That makes the header file update unnecessary too. > johannes ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
Re: [ath9k-devel] [PATCH] mac80211: ath9k: Use RCU protection calling ieee80211_get_tx_rates
Johannes Berg writes: > Now the subject should no longer say "mac80211:" :) It did have a change to mac80211.h as well, but IMHO that should be in a separate patch. -- Kalle Valo ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel