diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 189 |
1 files changed, 140 insertions, 49 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a6d21856b7e7..978f0037ed52 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -12,6 +12,7 @@ #include <linux/etherdevice.h> #include <linux/acpi.h> #include <linux/of.h> +#include <linux/bitfield.h> #include "hif.h" #include "core.h" @@ -2773,7 +2774,7 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, return -EINVAL; return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, - WMI_PEER_SMPS_STATE, + ar->wmi.peer_param->smps_state, ath10k_smps_map[smps]); } @@ -2930,7 +2931,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, * poked with peer param command. */ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, - WMI_PEER_DUMMY_VAR, 1); + ar->wmi.peer_param->dummy_var, 1); if (ret) { ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n", arvif->bssid, arvif->vdev_id, ret); @@ -3708,7 +3709,7 @@ static int ath10k_mac_tx(struct ath10k *ar, struct ieee80211_vif *vif, enum ath10k_hw_txrx_mode txmode, enum ath10k_mac_tx_path txpath, - struct sk_buff *skb) + struct sk_buff *skb, bool noque_offchan) { struct ieee80211_hw *hw = ar->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -3738,10 +3739,10 @@ static int ath10k_mac_tx(struct ath10k *ar, } } - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { + if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { if (!ath10k_mac_tx_frm_has_freq(ar)) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n", + skb, skb->len); skb_queue_tail(&ar->offchan_tx_queue, skb); ieee80211_queue_work(hw, &ar->offchan_tx_work); @@ -3803,8 +3804,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) mutex_lock(&ar->conf_mutex); - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n", + skb, skb->len); hdr = (struct ieee80211_hdr *)skb->data; peer_addr = ieee80211_get_DA(hdr); @@ -3850,7 +3851,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true); if (ret) { ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", ret); @@ -3860,8 +3861,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) time_left = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); if (time_left == 0) - ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n", - skb); + ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n", + skb, skb->len); if (!peer && tmp_peer_created) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); @@ -3903,8 +3904,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ar->running_fw->fw_file.fw_features)) { paddr = dma_map_single(ar->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (!paddr) + if (dma_mapping_error(ar->dev, paddr)) { + ieee80211_free_txskb(ar->hw, skb); continue; + } ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr); if (ret) { ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n", @@ -4065,7 +4068,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, if (ret) return ret; - skb = ieee80211_tx_dequeue(hw, txq); + skb = ieee80211_tx_dequeue_ni(hw, txq); if (!skb) { spin_lock_bh(&ar->htt.tx_lock); ath10k_htt_tx_dec_pending(htt); @@ -4097,7 +4100,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (unlikely(ret)) { ath10k_warn(ar, "failed to push frame: %d\n", ret); @@ -4378,7 +4381,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (ret) { ath10k_warn(ar, "failed to transmit frame: %d\n", ret); if (is_htt) { @@ -4754,6 +4757,63 @@ static int __ath10k_fetch_bb_timing_dt(struct ath10k *ar, return 0; } +static int ath10k_mac_rfkill_config(struct ath10k *ar) +{ + u32 param; + int ret; + + if (ar->hw_values->rfkill_pin == 0) { + ath10k_warn(ar, "ath10k does not support hardware rfkill with this device\n"); + return -EOPNOTSUPP; + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", + ar->hw_values->rfkill_pin, ar->hw_values->rfkill_cfg, + ar->hw_values->rfkill_on_level); + + param = FIELD_PREP(WMI_TLV_RFKILL_CFG_RADIO_LEVEL, + ar->hw_values->rfkill_on_level) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM, + ar->hw_values->rfkill_pin) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_PIN_AS_GPIO, + ar->hw_values->rfkill_cfg); + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->rfkill_config, + param); + if (ret) { + ath10k_warn(ar, + "failed to set rfkill config 0x%x: %d\n", + param, ret); + return ret; + } + return 0; +} + +int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable) +{ + enum wmi_tlv_rfkill_enable_radio param; + int ret; + + if (enable) + param = WMI_TLV_RFKILL_ENABLE_RADIO_ON; + else + param = WMI_TLV_RFKILL_ENABLE_RADIO_OFF; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac rfkill enable %d", param); + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rfkill_enable, + param); + if (ret) { + ath10k_warn(ar, "failed to set rfkill enable param %d: %d\n", + param, ret); + return ret; + } + + return 0; +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -4788,6 +4848,16 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err; } + spin_lock_bh(&ar->data_lock); + + if (ar->hw_rfkill_on) { + ar->hw_rfkill_on = false; + spin_unlock_bh(&ar->data_lock); + goto err; + } + + spin_unlock_bh(&ar->data_lock); + ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "Could not init hif: %d\n", ret); @@ -4801,6 +4871,14 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_power_down; } + if (ar->sys_cap_info & WMI_TLV_SYS_CAP_INFO_RFKILL) { + ret = ath10k_mac_rfkill_config(ar); + if (ret && ret != -EOPNOTSUPP) { + ath10k_warn(ar, "failed to configure rfkill: %d", ret); + goto err_core_stop; + } + } + param = ar->wmi.pdev_param->pmf_qos; ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { @@ -4960,7 +5038,8 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); if (ar->state != ATH10K_STATE_OFF) { - ath10k_halt(ar); + if (!ar->hw_rfkill_on) + ath10k_halt(ar); ar->state = ATH10K_STATE_OFF; } mutex_unlock(&ar->conf_mutex); @@ -5635,6 +5714,37 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static void ath10k_recalculate_mgmt_rate(struct ath10k *ar, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *def) +{ + struct ath10k_vif *arvif = (void *)vif->drv_priv; + const struct ieee80211_supported_band *sband; + u8 basic_rate_idx; + int hw_rate_code; + u32 vdev_param; + u16 bitrate; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + sband = ar->hw->wiphy->bands[def->chan->band]; + basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; + bitrate = sband->bitrates[basic_rate_idx].bitrate; + + hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); + if (hw_rate_code < 0) { + ath10k_warn(ar, "bitrate not supported %d\n", bitrate); + return; + } + + vdev_param = ar->wmi.vdev_param->mgmt_rate; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + hw_rate_code); + if (ret) + ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); +} + static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -5645,10 +5755,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct cfg80211_chan_def def; u32 vdev_param, pdev_param, slottime, preamble; u16 bitrate, hw_value; - u8 rate, basic_rate_idx, rateidx; - int ret = 0, hw_rate_code, mcast_rate; + u8 rate, rateidx; + int ret = 0, mcast_rate; enum nl80211_band band; - const struct ieee80211_supported_band *sband; mutex_lock(&ar->conf_mutex); @@ -5872,29 +5981,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, ret); } - if (changed & BSS_CHANGED_BASIC_RATES) { - if (ath10k_mac_vif_chan(vif, &def)) { - mutex_unlock(&ar->conf_mutex); - return; - } - - sband = ar->hw->wiphy->bands[def.chan->band]; - basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; - bitrate = sband->bitrates[basic_rate_idx].bitrate; - - hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); - if (hw_rate_code < 0) { - ath10k_warn(ar, "bitrate not supported %d\n", bitrate); - mutex_unlock(&ar->conf_mutex); - return; - } - - vdev_param = ar->wmi.vdev_param->mgmt_rate; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - hw_rate_code); - if (ret) - ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); - } + if (changed & BSS_CHANGED_BASIC_RATES && + !ath10k_mac_vif_chan(arvif->vif, &def)) + ath10k_recalculate_mgmt_rate(ar, vif, &def); mutex_unlock(&ar->conf_mutex); } @@ -6239,7 +6328,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (sta && sta->tdls) ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_AUTHORIZE, 1); + ar->wmi.peer_param->authorize, 1); exit: mutex_unlock(&ar->conf_mutex); @@ -6330,7 +6419,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, bw, mode); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_PHYMODE, mode); + ar->wmi.peer_param->phymode, mode); if (err) { ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n", sta->addr, mode, err); @@ -6338,7 +6427,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) } err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_CHAN_WIDTH, bw); + ar->wmi.peer_param->chan_width, bw); if (err) ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", sta->addr, bw, err); @@ -6349,7 +6438,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, nss); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_NSS, nss); + ar->wmi.peer_param->nss, nss); if (err) ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", sta->addr, nss, err); @@ -6360,7 +6449,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_SMPS_STATE, smps); + ar->wmi.peer_param->smps_state, smps); if (err) ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", sta->addr, smps, err); @@ -6434,7 +6523,7 @@ static int ath10k_sta_set_txpwr(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_USE_FIXED_PWR, txpwr); + ar->wmi.peer_param->use_fixed_power, txpwr); if (ret) { ath10k_warn(ar, "failed to set tx power for station ret: %d\n", ret); @@ -6515,6 +6604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL); if (!arsta->tx_stats) { + ath10k_mac_dec_num_stations(arvif, sta); ret = -ENOMEM; goto exit; } @@ -7419,7 +7509,7 @@ static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar, err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_PARAM_FIXED_RATE, rate); if (err) - ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n", + ath10k_warn(ar, "failed to enable STA %pM peer fixed rate: %d\n", sta->addr, err); return true; @@ -8868,6 +8958,7 @@ int ath10k_mac_register(struct ath10k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL); if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) |