Loading drivers/net/wireless/ath/ath10k/core.c +17 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .has_shifted_cc_wraparound = true, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, Loading Loading @@ -1084,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) if (status) goto err; /* Some of of qca988x solutions are having global reset issue * during target initialization. Bypassing PLL setting before * downloading firmware and letting the SoC run on REF_CLK is * fixing the problem. Corresponding firmware change is also needed * to set the clock source once the target is initialized. */ if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, ar->fw_features)) { status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); if (status) { ath10k_err(ar, "could not write to skip_clock_init: %d\n", status); goto err; } } status = ath10k_download_fw(ar, mode); if (status) goto err; Loading drivers/net/wireless/ath/ath10k/core.h +18 −9 Original line number Diff line number Diff line Loading @@ -284,15 +284,6 @@ struct ath10k_sta { #endif }; struct ath10k_chanctx { /* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally * mac80211 should allow some sort of explicit locking to guarantee * that the publicly available chanctx_conf can be accessed safely at * all times. */ struct ieee80211_chanctx_conf conf; }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) enum ath10k_beacon_state { Loading Loading @@ -468,6 +459,9 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, /* keep last */ ATH10K_FW_FEATURE_COUNT, }; Loading Loading @@ -577,6 +571,13 @@ struct ath10k { u32 patch_load_addr; int uart_pin; /* This is true if given HW chip has a quirky Cycle Counter * wraparound which resets to 0x7fffffff instead of 0. All * other CC related counters (e.g. Rx Clear Count) are divided * by 2 so they never wraparound themselves. */ bool has_shifted_cc_wraparound; struct ath10k_hw_params_fw { const char *dir; const char *fw; Loading Loading @@ -694,6 +695,14 @@ struct ath10k { u32 survey_last_cycle_count; struct survey_info survey[ATH10K_NUM_CHANS]; /* Channel info events are expected to come in pairs without and with * COMPLETE flag set respectively for each channel visit during scan. * * However there are deviations from this rule. This flag is used to * avoid reporting garbage data. */ bool ch_info_can_report_survey; struct dfs_pattern_detector *dfs_detector; unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */ Loading drivers/net/wireless/ath/ath10k/hw.c +21 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <linux/types.h> #include "core.h" #include "hw.h" const struct ath10k_hw_regs qca988x_regs = { Loading Loading @@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_chip_id_address = 0x000f0, .scratch_3_address = 0x0028, }; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { u32 cc_fix = 0; survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) { cc_fix = 0x7fffffff; survey->filled &= ~SURVEY_INFO_TIME_BUSY; } cc -= cc_prev - cc_fix; rcc -= rcc_prev; survey->time = CCNT_TO_MSEC(cc); survey->time_busy = CCNT_TO_MSEC(rcc); } drivers/net/wireless/ath/ath10k/hw.h +6 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,9 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) Loading Loading @@ -449,6 +452,9 @@ enum ath10k_hw_rate_cck { #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 /* Cycle counters are running at 88MHz */ #define CCNT_TO_MSEC(x) ((x) / 88000) /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_IND_EVENT_PENDING 1 Loading drivers/net/wireless/ath/ath10k/mac.c +82 −129 Original line number Diff line number Diff line Loading @@ -3949,83 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } static void ath10k_mac_chan_reconfigure(struct ath10k *ar) { struct ath10k_vif *arvif; struct cfg80211_chan_def def; int ret; lockdep_assert_held(&ar->conf_mutex); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chan reconfigure\n"); /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ if (ar->monitor_started) ath10k_monitor_stop(ar); list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) continue; if (!arvif->is_up) continue; if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { ath10k_warn(ar, "failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } } /* all vdevs are downed now - attempt to restart and re-up them */ list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) continue; if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; ret = ath10k_mac_setup_bcn_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", ret); ret = ath10k_mac_setup_prb_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) continue; ret = ath10k_vdev_restart(arvif, &def); if (ret) { ath10k_warn(ar, "failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } if (!arvif->is_up) continue; ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { ath10k_warn(ar, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_monitor_recalc(ar); } static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) { int ret; Loading Loading @@ -6144,7 +6067,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw, } static void ath10k_mac_update_rx_channel(struct ath10k *ar) ath10k_mac_update_rx_channel(struct ath10k *ar, struct ieee80211_chanctx_conf *ctx, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs) { struct cfg80211_chan_def *def = NULL; Loading @@ -6154,6 +6080,9 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->data_lock); WARN_ON(ctx && vifs); WARN_ON(vifs && n_vifs != 1); /* FIXME: Sort of an optimization and a workaround. Peers and vifs are * on a linked list now. Doing a lookup peer -> vif -> chanctx for each * ppdu on Rx may reduce performance on low-end systems. It should be Loading @@ -6165,36 +6094,28 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) * affected much. */ rcu_read_lock(); if (ath10k_mac_num_chanctxs(ar) == 1) { if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { ieee80211_iter_chan_contexts_atomic(ar->hw, ath10k_mac_get_any_chandef_iter, &def); if (vifs) def = &vifs[0].new_ctx->def; ar->rx_channel = def->chan; } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) { ar->rx_channel = ctx->def.chan; } else { ar->rx_channel = NULL; } rcu_read_unlock(); } static void ath10k_mac_chan_ctx_init(struct ath10k *ar, struct ath10k_chanctx *arctx, struct ieee80211_chanctx_conf *conf) { lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->data_lock); memset(arctx, 0, sizeof(*arctx)); arctx->conf = *conf; } static int ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx add freq %hu width %d ptr %p\n", Loading @@ -6203,8 +6124,7 @@ ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); ath10k_mac_chan_ctx_init(ar, arctx, ctx); ath10k_mac_update_rx_channel(ar); ath10k_mac_update_rx_channel(ar, ctx, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); Loading @@ -6228,7 +6148,7 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); ath10k_mac_update_rx_channel(ar); ath10k_mac_update_rx_channel(ar, NULL, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); Loading @@ -6243,16 +6163,12 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; mutex_lock(&ar->conf_mutex); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx change freq %hu->%hu width %d->%d ptr %p changed %x\n", arctx->conf.def.chan->center_freq, ctx->def.chan->center_freq, arctx->conf.def.width, ctx->def.width, ctx, changed); "mac chanctx change freq %hu width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use * switch_vif_chanctx(). Loading @@ -6260,10 +6176,6 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) goto unlock; spin_lock_bh(&ar->data_lock); arctx->conf = *ctx; spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); /* FIXME: How to configure Rx chains properly? */ Loading @@ -6283,7 +6195,6 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; int ret; Loading @@ -6298,11 +6209,11 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, return -EBUSY; } ret = ath10k_vdev_start(arvif, &arctx->conf.def); ret = ath10k_vdev_start(arvif, &ctx->def); if (ret) { ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n", arvif->vdev_id, vif->addr, arctx->conf.def.chan->center_freq, ret); ctx->def.chan->center_freq, ret); goto err; } Loading Loading @@ -6377,7 +6288,7 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif; struct ath10k_chanctx *arctx_new, *arctx_old; int ret; int i; mutex_lock(&ar->conf_mutex); Loading @@ -6386,38 +6297,81 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); spin_lock_bh(&ar->data_lock); /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ if (ar->monitor_started) ath10k_monitor_stop(ar); for (i = 0; i < n_vifs; i++) { arvif = ath10k_vif_to_arvif(vifs[i].vif); arctx_new = (void *)vifs[i].new_ctx->drv_priv; arctx_old = (void *)vifs[i].old_ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d ptr %p->%p\n", "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n", arvif->vdev_id, vifs[i].old_ctx->def.chan->center_freq, vifs[i].new_ctx->def.chan->center_freq, vifs[i].old_ctx->def.width, vifs[i].new_ctx->def.width, arctx_old, arctx_new); vifs[i].new_ctx->def.width); if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { ath10k_mac_chan_ctx_init(ar, arctx_new, vifs[i].new_ctx); } if (WARN_ON(!arvif->is_started)) continue; arctx_new->conf = *vifs[i].new_ctx; if (WARN_ON(!arvif->is_up)) continue; /* FIXME: ath10k_mac_chan_reconfigure() uses current, i.e. not * yet updated chanctx_conf pointer. */ arctx_old->conf = *vifs[i].new_ctx; ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { ath10k_warn(ar, "failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_mac_update_rx_channel(ar); /* All relevant vdevs are downed and associated channel resources * should be available for the channel switch now. */ spin_lock_bh(&ar->data_lock); ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs); spin_unlock_bh(&ar->data_lock); /* FIXME: Reconfigure only affected vifs */ ath10k_mac_chan_reconfigure(ar); for (i = 0; i < n_vifs; i++) { arvif = ath10k_vif_to_arvif(vifs[i].vif); if (WARN_ON(!arvif->is_started)) continue; if (WARN_ON(!arvif->is_up)) continue; ret = ath10k_mac_setup_bcn_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", ret); ret = ath10k_mac_setup_prb_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); if (ret) { ath10k_warn(ar, "failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { ath10k_warn(ar, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_monitor_recalc(ar); mutex_unlock(&ar->conf_mutex); return 0; Loading Loading @@ -6914,7 +6868,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->chanctx_data_size = sizeof(struct ath10k_chanctx); ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; Loading Loading
drivers/net/wireless/ath/ath10k/core.c +17 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .has_shifted_cc_wraparound = true, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, Loading Loading @@ -1084,6 +1085,22 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) if (status) goto err; /* Some of of qca988x solutions are having global reset issue * during target initialization. Bypassing PLL setting before * downloading firmware and letting the SoC run on REF_CLK is * fixing the problem. Corresponding firmware change is also needed * to set the clock source once the target is initialized. */ if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT, ar->fw_features)) { status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1); if (status) { ath10k_err(ar, "could not write to skip_clock_init: %d\n", status); goto err; } } status = ath10k_download_fw(ar, mode); if (status) goto err; Loading
drivers/net/wireless/ath/ath10k/core.h +18 −9 Original line number Diff line number Diff line Loading @@ -284,15 +284,6 @@ struct ath10k_sta { #endif }; struct ath10k_chanctx { /* Used to story copy of chanctx_conf to avoid inconsistencies. Ideally * mac80211 should allow some sort of explicit locking to guarantee * that the publicly available chanctx_conf can be accessed safely at * all times. */ struct ieee80211_chanctx_conf conf; }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) enum ath10k_beacon_state { Loading Loading @@ -468,6 +459,9 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, /* keep last */ ATH10K_FW_FEATURE_COUNT, }; Loading Loading @@ -577,6 +571,13 @@ struct ath10k { u32 patch_load_addr; int uart_pin; /* This is true if given HW chip has a quirky Cycle Counter * wraparound which resets to 0x7fffffff instead of 0. All * other CC related counters (e.g. Rx Clear Count) are divided * by 2 so they never wraparound themselves. */ bool has_shifted_cc_wraparound; struct ath10k_hw_params_fw { const char *dir; const char *fw; Loading Loading @@ -694,6 +695,14 @@ struct ath10k { u32 survey_last_cycle_count; struct survey_info survey[ATH10K_NUM_CHANS]; /* Channel info events are expected to come in pairs without and with * COMPLETE flag set respectively for each channel visit during scan. * * However there are deviations from this rule. This flag is used to * avoid reporting garbage data. */ bool ch_info_can_report_survey; struct dfs_pattern_detector *dfs_detector; unsigned long tx_paused; /* see ATH10K_TX_PAUSE_ */ Loading
drivers/net/wireless/ath/ath10k/hw.c +21 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ #include <linux/types.h> #include "core.h" #include "hw.h" const struct ath10k_hw_regs qca988x_regs = { Loading Loading @@ -56,3 +57,23 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_chip_id_address = 0x000f0, .scratch_3_address = 0x0028, }; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { u32 cc_fix = 0; survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; if (ar->hw_params.has_shifted_cc_wraparound && cc < cc_prev) { cc_fix = 0x7fffffff; survey->filled &= ~SURVEY_INFO_TIME_BUSY; } cc -= cc_prev - cc_fix; rcc -= rcc_prev; survey->time = CCNT_TO_MSEC(cc); survey->time_busy = CCNT_TO_MSEC(rcc); }
drivers/net/wireless/ath/ath10k/hw.h +6 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,9 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) Loading Loading @@ -449,6 +452,9 @@ enum ath10k_hw_rate_cck { #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 /* Cycle counters are running at 88MHz */ #define CCNT_TO_MSEC(x) ((x) / 88000) /* Firmware indications to the Host via SCRATCH_3 register. */ #define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) #define FW_IND_EVENT_PENDING 1 Loading
drivers/net/wireless/ath/ath10k/mac.c +82 −129 Original line number Diff line number Diff line Loading @@ -3949,83 +3949,6 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } static void ath10k_mac_chan_reconfigure(struct ath10k *ar) { struct ath10k_vif *arvif; struct cfg80211_chan_def def; int ret; lockdep_assert_held(&ar->conf_mutex); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chan reconfigure\n"); /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ if (ar->monitor_started) ath10k_monitor_stop(ar); list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) continue; if (!arvif->is_up) continue; if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { ath10k_warn(ar, "failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } } /* all vdevs are downed now - attempt to restart and re-up them */ list_for_each_entry(arvif, &ar->arvifs, list) { if (!arvif->is_started) continue; if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) continue; ret = ath10k_mac_setup_bcn_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", ret); ret = ath10k_mac_setup_prb_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) continue; ret = ath10k_vdev_restart(arvif, &def); if (ret) { ath10k_warn(ar, "failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } if (!arvif->is_up) continue; ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { ath10k_warn(ar, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_monitor_recalc(ar); } static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) { int ret; Loading Loading @@ -6144,7 +6067,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw, } static void ath10k_mac_update_rx_channel(struct ath10k *ar) ath10k_mac_update_rx_channel(struct ath10k *ar, struct ieee80211_chanctx_conf *ctx, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs) { struct cfg80211_chan_def *def = NULL; Loading @@ -6154,6 +6080,9 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->data_lock); WARN_ON(ctx && vifs); WARN_ON(vifs && n_vifs != 1); /* FIXME: Sort of an optimization and a workaround. Peers and vifs are * on a linked list now. Doing a lookup peer -> vif -> chanctx for each * ppdu on Rx may reduce performance on low-end systems. It should be Loading @@ -6165,36 +6094,28 @@ ath10k_mac_update_rx_channel(struct ath10k *ar) * affected much. */ rcu_read_lock(); if (ath10k_mac_num_chanctxs(ar) == 1) { if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { ieee80211_iter_chan_contexts_atomic(ar->hw, ath10k_mac_get_any_chandef_iter, &def); if (vifs) def = &vifs[0].new_ctx->def; ar->rx_channel = def->chan; } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) { ar->rx_channel = ctx->def.chan; } else { ar->rx_channel = NULL; } rcu_read_unlock(); } static void ath10k_mac_chan_ctx_init(struct ath10k *ar, struct ath10k_chanctx *arctx, struct ieee80211_chanctx_conf *conf) { lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->data_lock); memset(arctx, 0, sizeof(*arctx)); arctx->conf = *conf; } static int ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx add freq %hu width %d ptr %p\n", Loading @@ -6203,8 +6124,7 @@ ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); ath10k_mac_chan_ctx_init(ar, arctx, ctx); ath10k_mac_update_rx_channel(ar); ath10k_mac_update_rx_channel(ar, ctx, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); Loading @@ -6228,7 +6148,7 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); ath10k_mac_update_rx_channel(ar); ath10k_mac_update_rx_channel(ar, NULL, NULL, 0); spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); Loading @@ -6243,16 +6163,12 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; mutex_lock(&ar->conf_mutex); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx change freq %hu->%hu width %d->%d ptr %p changed %x\n", arctx->conf.def.chan->center_freq, ctx->def.chan->center_freq, arctx->conf.def.width, ctx->def.width, ctx, changed); "mac chanctx change freq %hu width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use * switch_vif_chanctx(). Loading @@ -6260,10 +6176,6 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) goto unlock; spin_lock_bh(&ar->data_lock); arctx->conf = *ctx; spin_unlock_bh(&ar->data_lock); ath10k_recalc_radar_detection(ar); /* FIXME: How to configure Rx chains properly? */ Loading @@ -6283,7 +6195,6 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; struct ath10k_chanctx *arctx = (void *)ctx->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; int ret; Loading @@ -6298,11 +6209,11 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, return -EBUSY; } ret = ath10k_vdev_start(arvif, &arctx->conf.def); ret = ath10k_vdev_start(arvif, &ctx->def); if (ret) { ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n", arvif->vdev_id, vif->addr, arctx->conf.def.chan->center_freq, ret); ctx->def.chan->center_freq, ret); goto err; } Loading Loading @@ -6377,7 +6288,7 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif; struct ath10k_chanctx *arctx_new, *arctx_old; int ret; int i; mutex_lock(&ar->conf_mutex); Loading @@ -6386,38 +6297,81 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); spin_lock_bh(&ar->data_lock); /* First stop monitor interface. Some FW versions crash if there's a * lone monitor interface. */ if (ar->monitor_started) ath10k_monitor_stop(ar); for (i = 0; i < n_vifs; i++) { arvif = ath10k_vif_to_arvif(vifs[i].vif); arctx_new = (void *)vifs[i].new_ctx->drv_priv; arctx_old = (void *)vifs[i].old_ctx->drv_priv; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d ptr %p->%p\n", "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n", arvif->vdev_id, vifs[i].old_ctx->def.chan->center_freq, vifs[i].new_ctx->def.chan->center_freq, vifs[i].old_ctx->def.width, vifs[i].new_ctx->def.width, arctx_old, arctx_new); vifs[i].new_ctx->def.width); if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { ath10k_mac_chan_ctx_init(ar, arctx_new, vifs[i].new_ctx); } if (WARN_ON(!arvif->is_started)) continue; arctx_new->conf = *vifs[i].new_ctx; if (WARN_ON(!arvif->is_up)) continue; /* FIXME: ath10k_mac_chan_reconfigure() uses current, i.e. not * yet updated chanctx_conf pointer. */ arctx_old->conf = *vifs[i].new_ctx; ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); if (ret) { ath10k_warn(ar, "failed to down vdev %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_mac_update_rx_channel(ar); /* All relevant vdevs are downed and associated channel resources * should be available for the channel switch now. */ spin_lock_bh(&ar->data_lock); ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs); spin_unlock_bh(&ar->data_lock); /* FIXME: Reconfigure only affected vifs */ ath10k_mac_chan_reconfigure(ar); for (i = 0; i < n_vifs; i++) { arvif = ath10k_vif_to_arvif(vifs[i].vif); if (WARN_ON(!arvif->is_started)) continue; if (WARN_ON(!arvif->is_up)) continue; ret = ath10k_mac_setup_bcn_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", ret); ret = ath10k_mac_setup_prb_tmpl(arvif); if (ret) ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", ret); ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); if (ret) { ath10k_warn(ar, "failed to restart vdev %d: %d\n", arvif->vdev_id, ret); continue; } ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { ath10k_warn(ar, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); continue; } } ath10k_monitor_recalc(ar); mutex_unlock(&ar->conf_mutex); return 0; Loading Loading @@ -6914,7 +6868,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->vif_data_size = sizeof(struct ath10k_vif); ar->hw->sta_data_size = sizeof(struct ath10k_sta); ar->hw->chanctx_data_size = sizeof(struct ath10k_chanctx); ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; Loading