diff options
Diffstat (limited to 'drivers/net/wireless/ath')
39 files changed, 1411 insertions, 742 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index c18647b87f71..0eddb204d85b 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -39,7 +39,7 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC -#define CE_DESC_FLAGS_META_DATA_LSB 3 +#define CE_DESC_FLAGS_META_DATA_LSB 2 struct ce_desc { __le32 addr; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 310e12bc078a..c0e454bb6a8d 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -436,16 +436,16 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) static void ath10k_core_free_firmware_files(struct ath10k *ar) { - if (ar->board && !IS_ERR(ar->board)) + if (!IS_ERR(ar->board)) release_firmware(ar->board); - if (ar->otp && !IS_ERR(ar->otp)) + if (!IS_ERR(ar->otp)) release_firmware(ar->otp); - if (ar->firmware && !IS_ERR(ar->firmware)) + if (!IS_ERR(ar->firmware)) release_firmware(ar->firmware); - if (ar->cal_file && !IS_ERR(ar->cal_file)) + if (!IS_ERR(ar->cal_file)) release_firmware(ar->cal_file); ar->board = NULL; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d60e46fe6d19..f65310c3ba5f 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -159,6 +159,25 @@ struct ath10k_fw_stats_peer { u32 peer_rx_rate; /* 10x only */ }; +struct ath10k_fw_stats_vdev { + struct list_head list; + + u32 vdev_id; + u32 beacon_snr; + u32 data_snr; + u32 num_tx_frames[4]; + u32 num_rx_frames; + u32 num_tx_frames_retries[4]; + u32 num_tx_frames_failures[4]; + u32 num_rts_fail; + u32 num_rts_success; + u32 num_rx_err; + u32 num_rx_discard; + u32 num_tx_not_acked; + u32 tx_rate_history[10]; + u32 beacon_rssi_history[10]; +}; + struct ath10k_fw_stats_pdev { struct list_head list; @@ -220,6 +239,7 @@ struct ath10k_fw_stats_pdev { struct ath10k_fw_stats { struct list_head pdevs; + struct list_head vdevs; struct list_head peers; }; @@ -288,6 +308,7 @@ struct ath10k_vif { bool is_started; bool is_up; bool spectral_enabled; + bool ps; u32 aid; u8 bssid[ETH_ALEN]; @@ -413,6 +434,12 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_WMI_10_2 = 4, + /* Some firmware revisions lack proper multi-interface client powersave + * implementation. Enabling PS could result in connection drops, + * traffic stalls, etc. + */ + ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index d2281e5c2ffe..301081db1ef6 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -243,6 +243,16 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) } } +static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head) +{ + struct ath10k_fw_stats_vdev *i, *tmp; + + list_for_each_entry_safe(i, tmp, head, list) { + list_del(&i->list); + kfree(i); + } +} + static void ath10k_debug_fw_stats_peers_free(struct list_head *head) { struct ath10k_fw_stats_peer *i, *tmp; @@ -258,6 +268,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) spin_lock_bh(&ar->data_lock); ar->debug.fw_stats_done = false; ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); + ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); spin_unlock_bh(&ar->data_lock); } @@ -273,14 +284,27 @@ static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) return num; } +static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head) +{ + struct ath10k_fw_stats_vdev *i; + size_t num = 0; + + list_for_each_entry(i, head, list) + ++num; + + return num; +} + void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_fw_stats stats = {}; bool is_start, is_started, is_end; size_t num_peers; + size_t num_vdevs; int ret; INIT_LIST_HEAD(&stats.pdevs); + INIT_LIST_HEAD(&stats.vdevs); INIT_LIST_HEAD(&stats.peers); spin_lock_bh(&ar->data_lock); @@ -308,6 +332,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) } num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); + num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); is_start = (list_empty(&ar->debug.fw_stats.pdevs) && !list_empty(&stats.pdevs)); is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && @@ -330,7 +355,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) goto free; } + if (num_vdevs >= BITS_PER_LONG) { + ath10k_warn(ar, "dropping fw vdev stats\n"); + goto free; + } + list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); + list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); } complete(&ar->debug.fw_stats_complete); @@ -340,6 +371,7 @@ free: * resources if that is not the case. */ ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); + ath10k_debug_fw_stats_vdevs_free(&stats.vdevs); ath10k_debug_fw_stats_peers_free(&stats.peers); unlock: @@ -363,7 +395,10 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar) reinit_completion(&ar->debug.fw_stats_complete); - ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); + ret = ath10k_wmi_request_stats(ar, + WMI_STAT_PDEV | + WMI_STAT_VDEV | + WMI_STAT_PEER); if (ret) { ath10k_warn(ar, "could not request stats (%d)\n", ret); return ret; @@ -395,8 +430,11 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, unsigned int len = 0; unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; const struct ath10k_fw_stats_pdev *pdev; + const struct ath10k_fw_stats_vdev *vdev; const struct ath10k_fw_stats_peer *peer; size_t num_peers; + size_t num_vdevs; + int i; spin_lock_bh(&ar->data_lock); @@ -408,6 +446,7 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, } num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); + num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -531,6 +570,65 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", + "ath10k VDEV stats", num_vdevs); + len += scnprintf(buf + len, buf_len - len, "%30s\n\n", + "================="); + + list_for_each_entry(vdev, &fw_stats->vdevs, list) { + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "vdev id", vdev->vdev_id); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "beacon snr", vdev->beacon_snr); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "data snr", vdev->data_snr); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num rx frames", vdev->num_rx_frames); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num rts fail", vdev->num_rts_fail); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num rts success", vdev->num_rts_success); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num rx err", vdev->num_rx_err); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num rx discard", vdev->num_rx_discard); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "num tx not acked", vdev->num_tx_not_acked); + + for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++) + len += scnprintf(buf + len, buf_len - len, + "%25s [%02d] %u\n", + "num tx frames", i, + vdev->num_tx_frames[i]); + + for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++) + len += scnprintf(buf + len, buf_len - len, + "%25s [%02d] %u\n", + "num tx frames retries", i, + vdev->num_tx_frames_retries[i]); + + for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++) + len += scnprintf(buf + len, buf_len - len, + "%25s [%02d] %u\n", + "num tx frames failures", i, + vdev->num_tx_frames_failures[i]); + + for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++) + len += scnprintf(buf + len, buf_len - len, + "%25s [%02d] 0x%08x\n", + "tx rate history", i, + vdev->tx_rate_history[i]); + + for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++) + len += scnprintf(buf + len, buf_len - len, + "%25s [%02d] %u\n", + "beacon rssi history", i, + vdev->beacon_rssi_history[i]); + + len += scnprintf(buf + len, buf_len - len, "\n"); + } + + len += scnprintf(buf + len, buf_len - len, "\n"); + len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", "ath10k PEER stats", num_peers); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); @@ -1900,6 +1998,7 @@ int ath10k_debug_create(struct ath10k *ar) return -ENOMEM; INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); + INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.peers); return 0; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index c1da44f65a4d..01a2b384f358 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -176,7 +176,7 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt) * automatically balances load wrt to CPU power. * * This probably comes at a cost of lower maximum throughput but - * improves the avarage and stability. */ + * improves the average and stability. */ spin_lock_bh(&htt->rx_ring.lock); num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 6c364bb98924..5d2db069d46e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -611,7 +611,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n", vdev_id, ret); return ret; } @@ -658,7 +658,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ret = ath10k_vdev_setup_sync(ar); if (ret) - ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n", ar->monitor_vdev_id, ret); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", @@ -927,8 +927,9 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n", - arg.vdev_id, ret); + ath10k_warn(ar, + "failed to synchronize setup for vdev %i restart %d: %d\n", + arg.vdev_id, restart, ret); return ret; } @@ -966,7 +967,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ret = ath10k_vdev_setup_sync(ar); if (ret) { - ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n", + ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n", arvif->vdev_id, ret); return ret; } @@ -1253,6 +1254,20 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) return 0; } +static int ath10k_mac_ps_vif_count(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + int num = 0; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) + if (arvif->ps) + num++; + + return num; +} + static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; @@ -1262,13 +1277,24 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) enum wmi_sta_ps_mode psmode; int ret; int ps_timeout; + bool enable_ps; lockdep_assert_held(&arvif->ar->conf_mutex); if (arvif->vif->type != NL80211_IFTYPE_STATION) return 0; - if (vif->bss_conf.ps) { + enable_ps = arvif->ps; + + if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && + !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, + ar->fw_features)) { + ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", + arvif->vdev_id); + enable_ps = false; + } + + if (enable_ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -1781,6 +1807,68 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, ath10k_smps_map[smps]); } +static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta_vht_cap vht_cap) +{ + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + int ret; + u32 param; + u32 value; + + if (!(ar->vht_cap_info & + (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))) + return 0; + + param = ar->wmi.vdev_param->txbf; + value = 0; + + if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED)) + return 0; + + /* The following logic is correct. If a remote STA advertises support + * for being a beamformer then we should enable us being a beamformee. + */ + + if (ar->vht_cap_info & + (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) { + if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; + + if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; + } + + if (ar->vht_cap_info & + (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { + if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; + + if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) + value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; + } + + if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; + + if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER) + value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; + + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value); + if (ret) { + ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n", + value, ret); + return ret; + } + + return 0; +} + /* can be called only in mac80211 callbacks due to `key_count` usage */ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1789,6 +1877,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ieee80211_sta_ht_cap ht_cap; + struct ieee80211_sta_vht_cap vht_cap; struct wmi_peer_assoc_complete_arg peer_arg; struct ieee80211_sta *ap_sta; int ret; @@ -1811,6 +1900,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, /* ap_sta must be accessed only within rcu section which must be left * before calling ath10k_setup_peer_smps() which might sleep. */ ht_cap = ap_sta->ht_cap; + vht_cap = ap_sta->vht_cap; ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); if (ret) { @@ -1836,6 +1926,13 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, return; } + ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); + if (ret) { + ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n", + arvif->vdev_id, bss_conf->bssid, ret); + return; + } + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); @@ -1853,6 +1950,18 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, } arvif->is_up = true; + + /* Workaround: Some firmware revisions (tested with qca6174 + * WLAN.RM.2.0-00073) have buggy powersave state machine and must be + * poked with peer param command. + */ + ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, + WMI_PEER_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); + return; + } } static void ath10k_bss_disassoc(struct ieee80211_hw *hw, @@ -1860,6 +1969,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct ieee80211_sta_vht_cap vht_cap = {}; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -1874,6 +1984,13 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, arvif->def_wep_key_idx = -1; + ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); + if (ret) { + ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n", + arvif->vdev_id, ret); + return; + } + arvif->is_up = false; } @@ -2554,6 +2671,17 @@ static int ath10k_start_scan(struct ath10k *ar, return -ETIMEDOUT; } + /* If we failed to start the scan, return error code at + * this point. This is probably due to some issue in the + * firmware, but no need to wedge the driver due to that... + */ + spin_lock_bh(&ar->data_lock); + if (ar->scan.state == ATH10K_SCAN_IDLE) { + spin_unlock_bh(&ar->data_lock); + return -EINVAL; + } + spin_unlock_bh(&ar->data_lock); + /* Add a 200ms margin to account for event/command processing */ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, msecs_to_jiffies(arg->max_scan_time+200)); @@ -3323,9 +3451,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, list_del(&arvif->list); if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); + ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, + vif->addr); if (ret) - ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n", + ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n", arvif->vdev_id, ret); kfree(arvif->u.ap.noa_data); @@ -3339,6 +3468,21 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", arvif->vdev_id, ret); + /* Some firmware revisions don't notify host about self-peer removal + * until after associated vdev is deleted. + */ + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id, + vif->addr); + if (ret) + ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n", + arvif->vdev_id, ret); + + spin_lock_bh(&ar->data_lock); + ar->num_peers--; + spin_unlock_bh(&ar->data_lock); + } + ath10k_peer_cleanup(ar, arvif->vdev_id); mutex_unlock(&ar->conf_mutex); @@ -3534,7 +3678,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_PS) { - ret = ath10k_mac_vif_setup_ps(arvif); + arvif->ps = vif->bss_conf.ps; + + ret = ath10k_config_ps(ar); if (ret) ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", arvif->vdev_id, ret); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e6972b09333e..7681237fe298 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -104,7 +104,7 @@ static const struct ce_attr host_ce_config_wlan[] = { { .flags = CE_ATTR_FLAGS, .src_nentries = 0, - .src_sz_max = 512, + .src_sz_max = 2048, .dest_nentries = 512, }, @@ -174,7 +174,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { .pipenum = __cpu_to_le32(1), .pipedir = __cpu_to_le32(PIPEDIR_IN), .nentries = __cpu_to_le32(32), - .nbytes_max = __cpu_to_le32(512), + .nbytes_max = __cpu_to_le32(2048), .flags = __cpu_to_le32(CE_ATTR_FLAGS), .reserved = __cpu_to_le32(0), }, diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 04dc4b9db04e..c8b64e7a6089 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -110,8 +110,7 @@ struct wmi_ops { bool deliver_cab); struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, const struct wmi_wmm_params_all_arg *arg); - struct sk_buff *(*gen_request_stats)(struct ath10k *ar, - enum wmi_stats_id stats_id); + struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask); struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, enum wmi_force_fw_hang_type type, u32 delay_ms); @@ -816,14 +815,14 @@ ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, } static inline int -ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask) { struct sk_buff *skb; if (!ar->wmi.ops->gen_request_stats) return -EOPNOTSUPP; - skb = ar->wmi.ops->gen_request_stats(ar, stats_id); + skb = ar->wmi.ops->gen_request_stats(ar, stats_mask); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 71614ba1b145..ee0c5f602e29 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -869,16 +869,57 @@ static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, return 0; } +static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src, + struct ath10k_fw_stats_vdev *dst) +{ + int i; + + dst->vdev_id = __le32_to_cpu(src->vdev_id); + dst->beacon_snr = __le32_to_cpu(src->beacon_snr); + dst->data_snr = __le32_to_cpu(src->data_snr); + dst->num_rx_frames = __le32_to_cpu(src->num_rx_frames); + dst->num_rts_fail = __le32_to_cpu(src->num_rts_fail); + dst->num_rts_success = __le32_to_cpu(src->num_rts_success); + dst->num_rx_err = __le32_to_cpu(src->num_rx_err); + dst->num_rx_discard = __le32_to_cpu(src->num_rx_discard); + dst->num_tx_not_acked = __le32_to_cpu(src->num_tx_not_acked); + + for (i = 0; i < ARRAY_SIZE(src->num_tx_frames); i++) + dst->num_tx_frames[i] = + __le32_to_cpu(src->num_tx_frames[i]); + + for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_retries); i++) + dst->num_tx_frames_retries[i] = + __le32_to_cpu(src->num_tx_frames_retries[i]); + + for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_failures); i++) + dst->num_tx_frames_failures[i] = + __le32_to_cpu(src->num_tx_frames_failures[i]); + + for (i = 0; i < ARRAY_SIZE(src->tx_rate_history); i++) + dst->tx_rate_history[i] = + __le32_to_cpu(src->tx_rate_history[i]); + + for (i = 0; i < ARRAY_SIZE(src->beacon_rssi_history); i++) + dst->beacon_rssi_history[i] = + __le32_to_cpu(src->beacon_rssi_history[i]); +} + static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, struct ath10k_fw_stats *stats) { const void **tb; - const struct wmi_stats_event *ev; + const struct wmi_tlv_stats_ev *ev; const void *data; - u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + u32 num_pdev_stats; + u32 num_vdev_stats; + u32 num_peer_stats; + u32 num_bcnflt_stats; + u32 num_chan_stats; size_t data_len; int ret; + int i; tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); if (IS_ERR(tb)) { @@ -899,8 +940,73 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats); + num_chan_stats = __le32_to_cpu(ev->num_chan_stats); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv stats update pdev %i vdev %i peer %i bcnflt %i chan %i\n", + num_pdev_stats, num_vdev_stats, num_peer_stats, + num_bcnflt_stats, num_chan_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = data; + if (data_len < sizeof(*src)) + return -EPROTO; + + data += sizeof(*src); + data_len -= sizeof(*src); + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + list_add_tail(&dst->list, &stats->pdevs); + } + + for (i = 0; i < num_vdev_stats; i++) { + const struct wmi_tlv_vdev_stats *src; + struct ath10k_fw_stats_vdev *dst; + + src = data; + if (data_len < sizeof(*src)) + return -EPROTO; + + data += sizeof(*src); + data_len -= sizeof(*src); + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; - WARN_ON(1); /* FIXME: not implemented yet */ + ath10k_wmi_tlv_pull_vdev_stats(src, dst); + list_add_tail(&dst->list, &stats->vdevs); + } + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10x_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = data; + if (data_len < sizeof(*src)) + return -EPROTO; + + data += sizeof(*src); + data_len -= sizeof(*src); + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->old, dst); + dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); + list_add_tail(&dst->list, &stats->peers); + } kfree(tb); return 0; @@ -1604,14 +1710,12 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, const struct wmi_wmm_params_all_arg *arg) { struct wmi_tlv_vdev_set_wmm_cmd *cmd; - struct wmi_wmm_params *wmm; struct wmi_tlv *tlv; struct sk_buff *skb; size_t len; void *ptr; - len = (sizeof(*tlv) + sizeof(*cmd)) + - (4 * (sizeof(*tlv) + sizeof(*wmm))); + len = sizeof(*tlv) + sizeof(*cmd); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) return ERR_PTR(-ENOMEM); @@ -1623,13 +1727,10 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, cmd = (void *)tlv->value; cmd->vdev_id = __cpu_to_le32(vdev_id); - ptr += sizeof(*tlv); - ptr += sizeof(*cmd); - - ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); - ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); - ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); - ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); + ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[0].params, &arg->ac_be); + ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[1].params, &arg->ac_bk); + ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[2].params, &arg->ac_vi); + ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[3].params, &arg->ac_vo); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n"); return skb; @@ -2080,8 +2181,7 @@ ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, - enum wmi_stats_id stats_id) +ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) { struct wmi_request_stats_cmd *cmd; struct wmi_tlv *tlv; @@ -2095,7 +2195,7 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD); tlv->len = __cpu_to_le16(sizeof(*cmd)); cmd = (void *)tlv->value; - cmd->stats_id = __cpu_to_le32(stats_id); + cmd->stats_id = __cpu_to_le32(stats_mask); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n"); return skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index de68fe76eae6..a6c8280cc4b1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1302,8 +1302,14 @@ struct wmi_tlv_pdev_set_wmm_cmd { __le32 dg_type; /* no idea.. */ } __packed; +struct wmi_tlv_vdev_wmm_params { + __le32 dummy; + struct wmi_wmm_params params; +} __packed; + struct wmi_tlv_vdev_set_wmm_cmd { __le32 vdev_id; + struct wmi_tlv_vdev_wmm_params vdev_wmm_params[4]; } __packed; struct wmi_tlv_phyerr_ev { @@ -1439,6 +1445,15 @@ struct wmi_tlv_sta_keepalive_cmd { __le32 interval; /* in seconds */ } __packed; +struct wmi_tlv_stats_ev { + __le32 stats_id; /* WMI_STAT_ */ + __le32 num_pdev_stats; + __le32 num_vdev_stats; + __le32 num_peer_stats; + __le32 num_bcnflt_stats; + __le32 num_chan_stats; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index aeea1c793943..c7ea77edce24 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1125,6 +1125,25 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar) } } +static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + switch (ar->scan.state) { + case ATH10K_SCAN_IDLE: + case ATH10K_SCAN_RUNNING: + case ATH10K_SCAN_ABORTING: + ath10k_warn(ar, "received scan start failed event in an invalid scan state: %s (%d)\n", + ath10k_scan_state_str(ar->scan.state), + ar->scan.state); + break; + case ATH10K_SCAN_STARTING: + complete(&ar->scan.started); + __ath10k_scan_finish(ar); + break; + } +} + static void ath10k_wmi_event_scan_completed(struct ath10k *ar) { lockdep_assert_held(&ar->data_lock); @@ -1292,6 +1311,7 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SCAN_EVENT_START_FAILED: ath10k_warn(ar, "received scan start failure event\n"); + ath10k_wmi_event_scan_start_failed(ar); break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: @@ -4954,7 +4974,7 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) { struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; @@ -4964,9 +4984,10 @@ ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) return ERR_PTR(-ENOMEM); cmd = (struct wmi_request_stats_cmd *)skb->data; - cmd->stats_id = __cpu_to_le32(stats_id); + cmd->stats_id = __cpu_to_le32(stats_mask); - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n", + stats_mask); return skb; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 20ce3603e64b..adf935bf0580 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3057,8 +3057,12 @@ struct wmi_pdev_stats_peer { } __packed; enum wmi_stats_id { - WMI_REQUEST_PEER_STAT = 0x01, - WMI_REQUEST_AP_STAT = 0x02 + WMI_STAT_PEER = BIT(0), + WMI_STAT_AP = BIT(1), + WMI_STAT_PDEV = BIT(2), + WMI_STAT_VDEV = BIT(3), + WMI_STAT_BCNFLT = BIT(4), + WMI_STAT_VDEV_RATE = BIT(5), }; struct wlan_inst_rssi_args { @@ -3093,7 +3097,7 @@ struct wmi_pdev_suspend_cmd { } __packed; struct wmi_stats_event { - __le32 stats_id; /* %WMI_REQUEST_ */ + __le32 stats_id; /* WMI_STAT_ */ /* * number of pdev stats event structures * (wmi_pdev_stats) 0 or 1 @@ -3745,6 +3749,11 @@ enum wmi_10x_vdev_param { WMI_10X_VDEV_PARAM_VHT80_RATEMASK, }; +#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) +#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) +#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) +#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) + /* slot time long */ #define WMI_VDEV_SLOT_TIME_LONG 0x1 /* slot time short */ @@ -4436,7 +4445,8 @@ enum wmi_peer_param { WMI_PEER_AUTHORIZE = 0x3, WMI_PEER_CHAN_WIDTH = 0x4, WMI_PEER_NSS = 0x5, - WMI_PEER_USE_4ADDR = 0x6 + WMI_PEER_USE_4ADDR = 0x6, + WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */ }; struct wmi_peer_set_param_cmd { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 7b94a6c7db3d..bd169fae32a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -284,12 +284,12 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) AR_MCI_INTERRUPT_RX_MSG_CONT_RST); REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); - if (mci->is_2g) { + if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { ar9003_mci_send_lna_transfer(ah, true); udelay(5); } - if ((mci->is_2g && !mci->update_2g5g)) { + if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, @@ -593,7 +593,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, if (!time_out) break; - offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) continue; @@ -657,7 +657,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, time_out = 0; while (more_data == MCI_GPM_MORE) { - offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) break; @@ -771,8 +771,14 @@ exit: static void ar9003_mci_mute_bt(struct ath_hw *ah) { + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + /* disable all MCI messages */ REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); /* wait pending HW messages to flush out */ @@ -783,9 +789,10 @@ static void ar9003_mci_mute_bt(struct ath_hw *ah) * 1. reset not after resuming from full sleep * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment */ - ar9003_mci_send_lna_take(ah, true); - - udelay(5); + if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { + ar9003_mci_send_lna_take(ah, true); + udelay(5); + } ar9003_mci_send_sys_sleeping(ah, true); } @@ -821,6 +828,80 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); } +static void ar9003_mci_stat_setup(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + if (!AR_SREV_9565(ah)) + return; + + if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) { + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_ENABLE, 1); + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_BT_LINKID, + MCI_STAT_ALL_BT_LINKID); + } else { + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_ENABLE, 0); + } +} + +static void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(1, AR_BTCOEX_CTRL_PA_SHARED) | + SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + +static void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(0, AR_BTCOEX_CTRL_PA_SHARED) | + SM(0, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0); + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + +static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(1, AR_BTCOEX_CTRL_PA_SHARED) | + SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, bool is_full_sleep) { @@ -831,11 +912,6 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", is_full_sleep, is_2g); - if (!mci->gpm_addr && !mci->sched_addr) { - ath_err(common, "MCI GPM and schedule buffers are not allocated\n"); - return -ENOMEM; - } - if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { ath_err(common, "BTCOEX control register is dead\n"); return -EINVAL; @@ -850,26 +926,17 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, * To avoid MCI state machine be affected by incoming remote MCI msgs, * MCI mode will be enabled later, right before reset the MCI TX and RX. */ - - regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | - SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | - SM(1, AR_BTCOEX_CTRL_PA_SHARED) | - SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | - SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | - SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | - SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); if (AR_SREV_9565(ah)) { - regval |= SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | - SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK); - REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, - AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); + u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); + + if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) + ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); + else + ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); } else { - regval |= SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | - SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK); + ar9003_mci_set_btcoex_ctrl_9462(ah); } - REG_WRITE(ah, AR_BTCOEX_CTRL, regval); - if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); else @@ -926,23 +993,26 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); - ar9003_mci_get_next_gpm_offset(ah, true, NULL); + /* Init GPM offset after MCI Reset Rx */ + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); - REG_CLR_BIT(ah, AR_MCI_TX_CTRL, - AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) + REG_CLR_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + else + REG_SET_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); ar9003_mci_observation_set_up(ah); mci->ready = true; ar9003_mci_prep_interface(ah); + ar9003_mci_stat_setup(ah); - if (AR_SREV_9565(ah)) - REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, - AR_MCI_DBG_CNT_CTRL_ENABLE, 0); if (en_int) ar9003_mci_enable_interrupt(ah); @@ -1218,6 +1288,14 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; + case MCI_STATE_INIT_GPM_OFFSET: + value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + + if (value < mci->gpm_len) + mci->gpm_idx = value; + else + mci->gpm_idx = 0; + break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); @@ -1364,21 +1442,11 @@ void ar9003_mci_check_gpm_offset(struct ath_hw *ah) mci->gpm_idx = 0; } -u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more) +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 offset, more_gpm = 0, gpm_ptr; - if (first) { - gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); - - if (gpm_ptr >= mci->gpm_len) - gpm_ptr = 0; - - mci->gpm_idx = gpm_ptr; - return gpm_ptr; - } - /* * This could be useful to avoid new GPM message interrupt which * may lead to spurious interrupt after power sleep, or multiple diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 66d7ab9f920d..e288611c12d5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -92,14 +92,36 @@ enum mci_gpm_coex_bt_update_flags_op { #define ATH_MCI_CONFIG_CLK_DIV 0x00003000 #define ATH_MCI_CONFIG_CLK_DIV_S 12 #define ATH_MCI_CONFIG_DISABLE_TUNING 0x00004000 +#define ATH_MCI_CONFIG_DISABLE_AIC 0x00008000 +#define ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN 0x007f0000 +#define ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN_S 16 +#define ATH_MCI_CONFIG_NO_QUIET_ACK 0x00800000 +#define ATH_MCI_CONFIG_NO_QUIET_ACK_S 23 +#define ATH_MCI_CONFIG_ANT_ARCH 0x07000000 +#define ATH_MCI_CONFIG_ANT_ARCH_S 24 +#define ATH_MCI_CONFIG_FORCE_QUIET_ACK 0x08000000 +#define ATH_MCI_CONFIG_FORCE_QUIET_ACK_S 27 +#define ATH_MCI_CONFIG_FORCE_2CHAIN_ACK 0x10000000 +#define ATH_MCI_CONFIG_MCI_STAT_DBG 0x20000000 #define ATH_MCI_CONFIG_MCI_WEIGHT_DBG 0x40000000 #define ATH_MCI_CONFIG_DISABLE_MCI 0x80000000 #define ATH_MCI_CONFIG_MCI_OBS_MASK (ATH_MCI_CONFIG_MCI_OBS_MCI | \ ATH_MCI_CONFIG_MCI_OBS_TXRX | \ ATH_MCI_CONFIG_MCI_OBS_BT) + #define ATH_MCI_CONFIG_MCI_OBS_GPIO 0x0000002F +#define ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_NON_SHARED 0x00 +#define ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED 0x01 +#define ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_NON_SHARED 0x02 +#define ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_SHARED 0x03 +#define ATH_MCI_ANT_ARCH_3_ANT 0x04 + +#define MCI_ANT_ARCH_PA_LNA_SHARED(mci) \ + ((MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH) == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) || \ + (MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH) == ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_SHARED)) + enum mci_message_header { /* length of payload */ MCI_LNA_CTRL = 0x10, /* len = 0 */ MCI_CONT_NACK = 0x20, /* len = 0 */ @@ -188,20 +210,55 @@ enum mci_bt_state { MCI_BT_CAL }; +enum mci_ps_state { + MCI_PS_DISABLE, + MCI_PS_ENABLE, + MCI_PS_ENABLE_OFF, + MCI_PS_ENABLE_ON +}; + /* Type of state query */ enum mci_state_type { MCI_STATE_ENABLE, + MCI_STATE_INIT_GPM_OFFSET, + MCI_STATE_CHECK_GPM_OFFSET, + MCI_STATE_NEXT_GPM_OFFSET, + MCI_STATE_LAST_GPM_OFFSET, + MCI_STATE_BT, + MCI_STATE_SET_BT_SLEEP, MCI_STATE_SET_BT_AWAKE, + MCI_STATE_SET_BT_CAL_START, + MCI_STATE_SET_BT_CAL, MCI_STATE_LAST_SCHD_MSG_OFFSET, MCI_STATE_REMOTE_SLEEP, + MCI_STATE_CONT_STATUS, MCI_STATE_RESET_REQ_WAKE, MCI_STATE_SEND_WLAN_COEX_VERSION, + MCI_STATE_SET_BT_COEX_VERSION, + MCI_STATE_SEND_WLAN_CHANNELS, MCI_STATE_SEND_VERSION_QUERY, MCI_STATE_SEND_STATUS_QUERY, + MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_SET_CONCUR_TX_PRI, MCI_STATE_RECOVER_RX, MCI_STATE_NEED_FTP_STOMP, + MCI_STATE_NEED_TUNING, + MCI_STATE_NEED_STAT_DEBUG, + MCI_STATE_SHARED_CHAIN_CONCUR_TX, + MCI_STATE_AIC_CAL, + MCI_STATE_AIC_START, + MCI_STATE_AIC_CAL_RESET, + MCI_STATE_AIC_CAL_SINGLE, + MCI_STATE_IS_AR9462, + MCI_STATE_IS_AR9565_1ANT, + MCI_STATE_IS_AR9565_2ANT, + MCI_STATE_WLAN_WEAK_SIGNAL, + MCI_STATE_SET_WLAN_PS_STATE, + MCI_STATE_GET_WLAN_PS_STATE, MCI_STATE_DEBUG, - MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_STAT_DEBUG, + MCI_STATE_ALLOW_FCS, + MCI_STATE_SET_2G_CONTENTION, MCI_STATE_MAX }; @@ -255,7 +312,7 @@ int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, void ar9003_mci_cleanup(struct ath_hw *ah); void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, u32 *rx_msg_intr); -u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more); +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more); void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor); void ar9003_mci_send_wlan_channels(struct ath_hw *ah); /* diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 86bfc9604dca..bea41df9fbd7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -20,11 +20,25 @@ #include "reg_wow.h" #include "hw-ops.h" +static void ath9k_hw_set_sta_powersave(struct ath_hw *ah) +{ + if (!ath9k_hw_mci_is_enabled(ah)) + goto set; + /* + * If MCI is being used, set PWR_SAV only when MCI's + * PS state is disabled. + */ + if (ar9003_mci_state(ah, MCI_STATE_GET_WLAN_PS_STATE) != MCI_PS_DISABLE) + return; +set: + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); +} + static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + ath9k_hw_set_sta_powersave(ah); /* set rx disable bit */ REG_WRITE(ah, AR_CR, AR_CR_RXD); @@ -44,6 +58,9 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); } + if (ath9k_hw_mci_is_enabled(ah)) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); } @@ -74,8 +91,6 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) for (i = 0; i < KAL_NUM_DESC_WORDS; i++) REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | @@ -88,9 +103,11 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - if (AR_SREV_9462_20(ah)) { - /* AR9462 2.0 has an extra descriptor word (time based - * discard) compared to other chips */ + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565(ah)) { + /* + * AR9462 2.0 and AR9565 have an extra descriptor word + * (time based discard) compared to other chips. + */ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); wow_ka_data_word0 = AR_WOW_TXBUF(13); } else { @@ -99,7 +116,6 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) for (i = 0; i < KAL_NUM_DATA_WORDS; i++) REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); - } int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, @@ -170,18 +186,17 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) u32 val = 0, rval; /* - * read the WoW status register to know - * the wakeup reason + * Read the WoW status register to know + * the wakeup reason. */ rval = REG_READ(ah, AR_WOW_PATTERN); val = AR_WOW_STATUS(rval); /* - * mask only the WoW events that we have enabled. Sometimes + * Mask only the WoW events that we have enabled. Sometimes * we have spurious WoW events from the AR_WOW_PATTERN * register. This mask will clean it up. */ - val &= ah->wow.wow_event_mask; if (val) { @@ -195,6 +210,15 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) wow_status |= AH_WOW_BEACON_MISS; } + rval = REG_READ(ah, AR_MAC_PCU_WOW4); + val = AR_WOW_STATUS2(rval); + val &= ah->wow.wow_event_mask2; + + if (val) { + if (AR_WOW2_PATTERN_FOUND(val)) + wow_status |= AH_WOW_USER_PATTERN_EN; + } + /* * set and clear WOW_PME_CLEAR registers for the chip to * generate next wow signal. @@ -206,10 +230,12 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) AR_PMCTRL_PWR_STATE_D1D3); /* - * clear all events + * Clear all events. */ REG_WRITE(ah, AR_WOW_PATTERN, AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + REG_WRITE(ah, AR_MAC_PCU_WOW4, + AR_WOW_CLEAR_EVENTS2(REG_READ(ah, AR_MAC_PCU_WOW4))); /* * restore the beacon threshold to init value @@ -226,7 +252,15 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, false); + if (AR_SREV_9462(ah) || AR_SREV_9565(ah) || AR_SREV_9485(ah)) { + u32 dc = REG_READ(ah, AR_DIRECT_CONNECT); + + if (!(dc & AR_DC_TSF2_ENABLE)) + ath9k_hw_gen_timer_start_tsf2(ah); + } + ah->wow.wow_event_mask = 0; + ah->wow.wow_event_mask2 = 0; return wow_status; } @@ -408,6 +442,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) ath9k_hw_wow_set_arwr_reg(ah); + if (ath9k_hw_mci_is_enabled(ah)) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + /* HW WoW */ REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5)); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0f8e9464e4ab..7e89236c0e13 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -645,6 +645,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc, struct ath9k_vif_iter_data *iter_data); void ath9k_calculate_summary_state(struct ath_softc *sc, struct ath_chanctx *ctx); +void ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif); /*******************/ /* Beacon Handling */ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 3dfc2c7f1f07..5a084d94ed90 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -103,7 +103,9 @@ void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) return; } - if (AR_SREV_9300_20_OR_LATER(ah)) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; + } else if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; @@ -307,6 +309,18 @@ static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah) btcoex->enabled = true; } +static void ath9k_hw_btcoex_disable_mci(struct ath_hw *ah) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + int i; + + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); + + for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) + REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), + btcoex_hw->wlan_weight[i]); +} + void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -318,17 +332,18 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) ath9k_hw_btcoex_enable_2wire(ah); break; case ATH_BTCOEX_CFG_3WIRE: - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - ath9k_hw_btcoex_enable_mci(ah); - return; - } ath9k_hw_btcoex_enable_3wire(ah); break; + case ATH_BTCOEX_CFG_MCI: + ath9k_hw_btcoex_enable_mci(ah); + break; } - REG_RMW(ah, AR_GPIO_PDPU, - (0x2 << (btcoex_hw->btactive_gpio * 2)), - (0x3 << (btcoex_hw->btactive_gpio * 2))); + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) { + REG_RMW(ah, AR_GPIO_PDPU, + (0x2 << (btcoex_hw->btactive_gpio * 2)), + (0x3 << (btcoex_hw->btactive_gpio * 2))); + } ah->btcoex_hw.enabled = true; } @@ -340,14 +355,14 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) int i; btcoex_hw->enabled = false; - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); - for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) - REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), - btcoex_hw->wlan_weight[i]); + + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) { + ath9k_hw_btcoex_disable_mci(ah); return; } - ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); + + if (!AR_SREV_9300_20_OR_LATER(ah)) + ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 6de26ea5d5fa..5fe62ff2223b 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -58,6 +58,7 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, ATH_BTCOEX_CFG_3WIRE, + ATH_BTCOEX_CFG_MCI, }; struct ath9k_hw_mci { diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 50a2e0ac3b8b..dbf8f4959642 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1156,7 +1156,10 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf, if (tpc_enabled != ah->tpc_enabled) { ah->tpc_enabled = tpc_enabled; - ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + + mutex_lock(&sc->mutex); + ath9k_set_txpower(sc, NULL); + mutex_unlock(&sc->mutex); } return count; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index da344b27326c..86d46c196966 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -202,17 +202,16 @@ static void ath_btcoex_period_timer(unsigned long data) } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - ath9k_mci_update_rssi(sc); - ath9k_ps_wakeup(sc); + spin_lock_bh(&btcoex->btcoex_lock); - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath_detect_bt_priority(sc); - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + ath9k_mci_update_rssi(sc); ath_mci_ftp_adjust(sc); + } - spin_lock_bh(&btcoex->btcoex_lock); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath_detect_bt_priority(sc); stomp_type = btcoex->bt_stomp_type; timer_period = btcoex->btcoex_no_stomp; @@ -252,9 +251,6 @@ static void ath_btcoex_no_stomp_timer(unsigned long arg) struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_common *common = ath9k_hw_common(ah); - - ath_dbg(common, BTCOEX, "no stomp timer running\n"); ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); @@ -271,7 +267,7 @@ static void ath_btcoex_no_stomp_timer(unsigned long arg) ath9k_ps_restore(sc); } -static int ath_init_btcoex_timer(struct ath_softc *sc) +static void ath_init_btcoex_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; @@ -280,6 +276,7 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) btcoex->btcoex_period / 100; btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * btcoex->btcoex_period / 100; + btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, (unsigned long) sc); @@ -287,8 +284,6 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) (unsigned long) sc); spin_lock_init(&btcoex->btcoex_lock); - - return 0; } /* @@ -299,6 +294,10 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) + return; + ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); /* make sure duty cycle timer is also stopped when resuming */ @@ -312,13 +311,19 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) mod_timer(&btcoex->period_timer, jiffies); } - /* * Pause btcoex timer and bt duty cycle timer */ void ath9k_btcoex_timer_pause(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) + return; + + ath_dbg(ath9k_hw_common(ah), BTCOEX, "Stopping btcoex timers\n"); del_timer_sync(&btcoex->period_timer); del_timer_sync(&btcoex->no_stomp_timer); @@ -356,33 +361,33 @@ void ath9k_start_btcoex(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && - !ah->btcoex_hw.enabled) { - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT, 0); - else - ath9k_hw_btcoex_set_weight(ah, 0, 0, - ATH_BTCOEX_STOMP_NONE); - ath9k_hw_btcoex_enable(ah); + if (ah->btcoex_hw.enabled || + ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) + return; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_resume(sc); - } + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT, 0); + else + ath9k_hw_btcoex_set_weight(ah, 0, 0, + ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_enable(ah); + ath9k_btcoex_timer_resume(sc); } void ath9k_stop_btcoex(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_pause(sc); - ath9k_hw_btcoex_disable(ah); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - ath_mci_flush_profile(&sc->btcoex.mci); - } + if (!ah->btcoex_hw.enabled || + ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) + return; + + ath9k_btcoex_timer_pause(sc); + ath9k_hw_btcoex_disable(ah); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + ath_mci_flush_profile(&sc->btcoex.mci); } void ath9k_deinit_btcoex(struct ath_softc *sc) @@ -409,22 +414,20 @@ int ath9k_init_btcoex(struct ath_softc *sc) break; case ATH_BTCOEX_CFG_3WIRE: ath9k_hw_btcoex_init_3wire(sc->sc_ah); - r = ath_init_btcoex_timer(sc); - if (r) - return -1; + ath_init_btcoex_timer(sc); txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - if (ath9k_hw_mci_is_enabled(ah)) { - sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - INIT_LIST_HEAD(&sc->btcoex.mci.info); + break; + case ATH_BTCOEX_CFG_MCI: + ath_init_btcoex_timer(sc); - r = ath_mci_setup(sc); - if (r) - return r; + sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; + INIT_LIST_HEAD(&sc->btcoex.mci.info); + ath9k_hw_btcoex_init_mci(ah); - ath9k_hw_btcoex_init_mci(ah); - } + r = ath_mci_setup(sc); + if (r) + return r; break; default: diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8e7153b186ed..10c02f5cbc5e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -40,6 +40,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */ { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ + { USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */ { USB_DEVICE(0x0cf3, 0x7015), .driver_info = AR9287_USB }, /* Atheros */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e82e570de330..29a25d92add7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -27,6 +27,7 @@ #include "eeprom.h" #include "calib.h" #include "reg.h" +#include "reg_mci.h" #include "phy.h" #include "btcoex.h" #include "dynack.h" diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 93ed99a72542..b0badef71ce7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1172,6 +1172,38 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath9k_ps_restore(sc); } +static void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + int *power = (int *)data; + + if (*power < vif->bss_conf.txpower) + *power = vif->bss_conf.txpower; +} + +/* Called with sc->mutex held. */ +void ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + int power; + struct ath_hw *ah = sc->sc_ah; + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + + ath9k_ps_wakeup(sc); + if (ah->tpc_enabled) { + power = (vif) ? vif->bss_conf.txpower : -1; + ieee80211_iterate_active_interfaces_atomic( + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_tpc_vif_iter, &power); + if (power == -1) + power = sc->hw->conf.power_level; + } else { + power = sc->hw->conf.power_level; + } + sc->cur_chan->txpower = 2 * power; + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + sc->cur_chan->cur_txpower = reg->max_power_level; + ath9k_ps_restore(sc); +} + static void ath9k_assign_hw_queues(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1225,6 +1257,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_assign_hw_queues(hw, vif); + ath9k_set_txpower(sc, vif); + an->sc = sc; an->sta = NULL; an->vif = vif; @@ -1265,6 +1299,8 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath9k_assign_hw_queues(hw, vif); ath9k_calculate_summary_state(sc, avp->chanctx); + ath9k_set_txpower(sc, vif); + mutex_unlock(&sc->mutex); return 0; } @@ -1294,6 +1330,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_calculate_summary_state(sc, avp->chanctx); + ath9k_set_txpower(sc, NULL); + mutex_unlock(&sc->mutex); } @@ -1397,14 +1435,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } - if (changed & IEEE80211_CONF_CHANGE_POWER) { - ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); - sc->cur_chan->txpower = 2 * conf->power_level; - ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, - sc->cur_chan->txpower, - &sc->cur_chan->cur_txpower); - } - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -1764,6 +1794,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & CHECK_ANI) ath_check_ani(sc); + if (changed & BSS_CHANGED_TXPOWER) { + ath_dbg(common, CONFIG, "vif %pM power %d dbm power_type %d\n", + vif->addr, bss_conf->txpower, bss_conf->txpower_type); + ath9k_set_txpower(sc, vif); + } + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 3f7a11edb82a..66596b95273f 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -495,7 +495,7 @@ void ath_mci_intr(struct ath_softc *sc) ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) { - ar9003_mci_get_next_gpm_offset(ah, true, NULL); + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); return; } @@ -559,8 +559,7 @@ void ath_mci_intr(struct ath_softc *sc) return; pgpm = mci->gpm_buf.bf_addr; - offset = ar9003_mci_get_next_gpm_offset(ah, false, - &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) break; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 9587ec655680..1234399a43dd 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -2044,279 +2044,4 @@ enum { #define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 -/* MCI Registers */ - -#define AR_MCI_COMMAND0 0x1800 -#define AR_MCI_COMMAND0_HEADER 0xFF -#define AR_MCI_COMMAND0_HEADER_S 0 -#define AR_MCI_COMMAND0_LEN 0x1f00 -#define AR_MCI_COMMAND0_LEN_S 8 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 - -#define AR_MCI_COMMAND1 0x1804 - -#define AR_MCI_COMMAND2 0x1808 -#define AR_MCI_COMMAND2_RESET_TX 0x01 -#define AR_MCI_COMMAND2_RESET_TX_S 0 -#define AR_MCI_COMMAND2_RESET_RX 0x02 -#define AR_MCI_COMMAND2_RESET_RX_S 1 -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 - -#define AR_MCI_RX_CTRL 0x180c - -#define AR_MCI_TX_CTRL 0x1810 -/* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */ -#define AR_MCI_TX_CTRL_CLK_DIV 0x03 -#define AR_MCI_TX_CTRL_CLK_DIV_S 0 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 - -#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 - -#define AR_MCI_SCHD_TABLE_0 0x1818 -#define AR_MCI_SCHD_TABLE_1 0x181c -#define AR_MCI_GPM_0 0x1820 -#define AR_MCI_GPM_1 0x1824 -#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 -#define AR_MCI_GPM_WRITE_PTR_S 16 -#define AR_MCI_GPM_BUF_LEN 0x0000FFFF -#define AR_MCI_GPM_BUF_LEN_S 0 - -#define AR_MCI_INTERRUPT_RAW 0x1828 -#define AR_MCI_INTERRUPT_EN 0x182c -#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 -#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 -#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 -#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 -#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_S 9 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 -#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 -#define AR_MCI_INTERRUPT_BT_PRI_S 11 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 -#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 -#define AR_MCI_INTERRUPT_BT_FREQ_S 28 -#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 -#define AR_MCI_INTERRUPT_BT_STOMP_S 29 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 - -#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ - AR_MCI_INTERRUPT_RX_INVALID_HDR | \ - AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_MSG | \ - AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ - AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) - -#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) - -#define AR_MCI_REMOTE_CPU_INT 0x1830 -#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 -#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 -#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 -#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 -#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 -#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \ - AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_RST) - -#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ - AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ - AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ - AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ - AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) - -#define AR_MCI_CPU_INT 0x1840 - -#define AR_MCI_RX_STATUS 0x1844 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 -#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 -#define AR_MCI_RX_REMOTE_SLEEP_S 12 -#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 -#define AR_MCI_RX_MCI_CLK_REQ_S 13 - -#define AR_MCI_CONT_STATUS 0x1848 -#define AR_MCI_CONT_RSSI_POWER 0x000000FF -#define AR_MCI_CONT_RSSI_POWER_S 0 -#define AR_MCI_CONT_PRIORITY 0x0000FF00 -#define AR_MCI_CONT_PRIORITY_S 8 -#define AR_MCI_CONT_TXRX 0x00010000 -#define AR_MCI_CONT_TXRX_S 16 - -#define AR_MCI_BT_PRI0 0x184c -#define AR_MCI_BT_PRI1 0x1850 -#define AR_MCI_BT_PRI2 0x1854 -#define AR_MCI_BT_PRI3 0x1858 -#define AR_MCI_BT_PRI 0x185c -#define AR_MCI_WL_FREQ0 0x1860 -#define AR_MCI_WL_FREQ1 0x1864 -#define AR_MCI_WL_FREQ2 0x1868 -#define AR_MCI_GAIN 0x186c -#define AR_MCI_WBTIMER1 0x1870 -#define AR_MCI_WBTIMER2 0x1874 -#define AR_MCI_WBTIMER3 0x1878 -#define AR_MCI_WBTIMER4 0x187c -#define AR_MCI_MAXGAIN 0x1880 -#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 -#define AR_MCI_HW_SCHD_TBL_D0 0x1888 -#define AR_MCI_HW_SCHD_TBL_D1 0x188c -#define AR_MCI_HW_SCHD_TBL_D2 0x1890 -#define AR_MCI_HW_SCHD_TBL_D3 0x1894 -#define AR_MCI_TX_PAYLOAD0 0x1898 -#define AR_MCI_TX_PAYLOAD1 0x189c -#define AR_MCI_TX_PAYLOAD2 0x18a0 -#define AR_MCI_TX_PAYLOAD3 0x18a4 -#define AR_BTCOEX_WBTIMER 0x18a8 - -#define AR_BTCOEX_CTRL 0x18ac -#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 -#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 -#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 -#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 -#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 -#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 -#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 -#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 -#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 -#define AR_BTCOEX_CTRL_PA_SHARED_S 4 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 -#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 -#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 -#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 -#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 - -#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) -#define AR_BTCOEX_WL_LNA 0x1940 -#define AR_BTCOEX_RFGAIN_CTRL 0x1944 -#define AR_BTCOEX_WL_LNA_TIMEOUT 0x003FFFFF -#define AR_BTCOEX_WL_LNA_TIMEOUT_S 0 - -#define AR_BTCOEX_CTRL2 0x1948 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 - -#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 -#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 -#define AR_GLB_WLAN_UART_INTF_EN_S 17 -#define AR_GLB_DS_JTAG_DISABLE 0x00040000 -#define AR_GLB_DS_JTAG_DISABLE_S 18 - -#define AR_BTCOEX_RC 0x194c -#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) -#define AR_BTCOEX_DBG 0x1a50 -#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 -#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 - -#define AR_MCI_SCHD_TABLE_2 0x1a5c -#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 -#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 -#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 -#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 - -#define AR_BTCOEX_CTRL3 0x1a60 -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 - -#define AR_GLB_SWREG_DISCONT_MODE 0x2002c -#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3 - -#define AR_MCI_MISC 0x1a74 -#define AR_MCI_MISC_HW_FIX_EN 0x00000001 -#define AR_MCI_MISC_HW_FIX_EN_S 0 -#define AR_MCI_DBG_CNT_CTRL 0x1a78 -#define AR_MCI_DBG_CNT_CTRL_ENABLE 0x00000001 -#define AR_MCI_DBG_CNT_CTRL_ENABLE_S 0 - #endif diff --git a/drivers/net/wireless/ath/ath9k/reg_mci.h b/drivers/net/wireless/ath/ath9k/reg_mci.h new file mode 100644 index 000000000000..6251310704e3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_mci.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_MCI_H +#define REG_MCI_H + +#define AR_MCI_COMMAND0 0x1800 +#define AR_MCI_COMMAND0_HEADER 0xFF +#define AR_MCI_COMMAND0_HEADER_S 0 +#define AR_MCI_COMMAND0_LEN 0x1f00 +#define AR_MCI_COMMAND0_LEN_S 8 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 + +#define AR_MCI_COMMAND1 0x1804 + +#define AR_MCI_COMMAND2 0x1808 +#define AR_MCI_COMMAND2_RESET_TX 0x01 +#define AR_MCI_COMMAND2_RESET_TX_S 0 +#define AR_MCI_COMMAND2_RESET_RX 0x02 +#define AR_MCI_COMMAND2_RESET_RX_S 1 +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 + +#define AR_MCI_RX_CTRL 0x180c + +#define AR_MCI_TX_CTRL 0x1810 +/* + * 0 = no division, + * 1 = divide by 2, + * 2 = divide by 4, + * 3 = divide by 8 + */ +#define AR_MCI_TX_CTRL_CLK_DIV 0x03 +#define AR_MCI_TX_CTRL_CLK_DIV_S 0 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 + +#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 + +#define AR_MCI_SCHD_TABLE_0 0x1818 +#define AR_MCI_SCHD_TABLE_1 0x181c +#define AR_MCI_GPM_0 0x1820 +#define AR_MCI_GPM_1 0x1824 +#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 +#define AR_MCI_GPM_WRITE_PTR_S 16 +#define AR_MCI_GPM_BUF_LEN 0x0000FFFF +#define AR_MCI_GPM_BUF_LEN_S 0 + +#define AR_MCI_INTERRUPT_RAW 0x1828 + +#define AR_MCI_INTERRUPT_EN 0x182c +#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 +#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 +#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 +#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 +#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_S 9 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 +#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 +#define AR_MCI_INTERRUPT_BT_PRI_S 11 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 +#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 +#define AR_MCI_INTERRUPT_BT_FREQ_S 28 +#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 +#define AR_MCI_INTERRUPT_BT_STOMP_S 29 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 + +#define AR_MCI_REMOTE_CPU_INT 0x1830 +#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 +#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 +#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 +#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 +#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 + +#define AR_MCI_CPU_INT 0x1840 + +#define AR_MCI_RX_STATUS 0x1844 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 +#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 +#define AR_MCI_RX_REMOTE_SLEEP_S 12 +#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 +#define AR_MCI_RX_MCI_CLK_REQ_S 13 + +#define AR_MCI_CONT_STATUS 0x1848 +#define AR_MCI_CONT_RSSI_POWER 0x000000FF +#define AR_MCI_CONT_RSSI_POWER_S 0 +#define AR_MCI_CONT_PRIORITY 0x0000FF00 +#define AR_MCI_CONT_PRIORITY_S 8 +#define AR_MCI_CONT_TXRX 0x00010000 +#define AR_MCI_CONT_TXRX_S 16 + +#define AR_MCI_BT_PRI0 0x184c +#define AR_MCI_BT_PRI1 0x1850 +#define AR_MCI_BT_PRI2 0x1854 +#define AR_MCI_BT_PRI3 0x1858 +#define AR_MCI_BT_PRI 0x185c +#define AR_MCI_WL_FREQ0 0x1860 +#define AR_MCI_WL_FREQ1 0x1864 +#define AR_MCI_WL_FREQ2 0x1868 +#define AR_MCI_GAIN 0x186c +#define AR_MCI_WBTIMER1 0x1870 +#define AR_MCI_WBTIMER2 0x1874 +#define AR_MCI_WBTIMER3 0x1878 +#define AR_MCI_WBTIMER4 0x187c +#define AR_MCI_MAXGAIN 0x1880 +#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 +#define AR_MCI_HW_SCHD_TBL_D0 0x1888 +#define AR_MCI_HW_SCHD_TBL_D1 0x188c +#define AR_MCI_HW_SCHD_TBL_D2 0x1890 +#define AR_MCI_HW_SCHD_TBL_D3 0x1894 +#define AR_MCI_TX_PAYLOAD0 0x1898 +#define AR_MCI_TX_PAYLOAD1 0x189c +#define AR_MCI_TX_PAYLOAD2 0x18a0 +#define AR_MCI_TX_PAYLOAD3 0x18a4 +#define AR_BTCOEX_WBTIMER 0x18a8 + +#define AR_BTCOEX_CTRL 0x18ac +#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 +#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 +#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 +#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 +#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 +#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 +#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 +#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 +#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 +#define AR_BTCOEX_CTRL_PA_SHARED_S 4 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 +#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 +#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 +#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 +#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 + +#define AR_BTCOEX_WL_WEIGHTS0 0x18b0 +#define AR_BTCOEX_WL_WEIGHTS1 0x18b4 +#define AR_BTCOEX_WL_WEIGHTS2 0x18b8 +#define AR_BTCOEX_WL_WEIGHTS3 0x18bc + +#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) +#define AR_BTCOEX_WL_LNA 0x1940 +#define AR_BTCOEX_RFGAIN_CTRL 0x1944 +#define AR_BTCOEX_WL_LNA_TIMEOUT 0x003FFFFF +#define AR_BTCOEX_WL_LNA_TIMEOUT_S 0 + +#define AR_BTCOEX_CTRL2 0x1948 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 + +#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 +#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 +#define AR_GLB_WLAN_UART_INTF_EN_S 17 +#define AR_GLB_DS_JTAG_DISABLE 0x00040000 +#define AR_GLB_DS_JTAG_DISABLE_S 18 + +#define AR_BTCOEX_RC 0x194c +#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) +#define AR_BTCOEX_DBG 0x1a50 +#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 +#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 + +#define AR_MCI_SCHD_TABLE_2 0x1a5c +#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 +#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 +#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 +#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 + +#define AR_BTCOEX_CTRL3 0x1a60 +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 + +#define AR_GLB_SWREG_DISCONT_MODE 0x2002c +#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3 + +#define AR_MCI_MISC 0x1a74 +#define AR_MCI_MISC_HW_FIX_EN 0x00000001 +#define AR_MCI_MISC_HW_FIX_EN_S 0 + +#define AR_MCI_DBG_CNT_CTRL 0x1a78 +#define AR_MCI_DBG_CNT_CTRL_ENABLE 0x00000001 +#define AR_MCI_DBG_CNT_CTRL_ENABLE_S 0 +#define AR_MCI_DBG_CNT_CTRL_BT_LINKID 0x000007f8 +#define AR_MCI_DBG_CNT_CTRL_BT_LINKID_S 3 + +#define MCI_STAT_ALL_BT_LINKID 0xffff + +#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ + AR_MCI_INTERRUPT_RX_INVALID_HDR | \ + AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_MSG | \ + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ + AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) + +#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) + +#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_RST) + +#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | \ + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ + AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | \ + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) + +#endif /* REG_MCI_H */ diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h index 3abfca56ca58..453054078cc4 100644 --- a/drivers/net/wireless/ath/ath9k/reg_wow.h +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -72,7 +72,7 @@ #define AR_WOW_MAC_INTR_EN 0x00040000 #define AR_WOW_MAGIC_EN 0x00010000 #define AR_WOW_PATTERN_EN(x) (x & 0xff) -#define AR_WOW_PAT_FOUND_SHIFT 8 +#define AR_WOW_PAT_FOUND_SHIFT 8 #define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) #define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) #define AR_WOW_MAGIC_PAT_FOUND 0x00020000 @@ -90,6 +90,14 @@ AR_WOW_BEACON_FAIL | \ AR_WOW_KEEP_ALIVE_FAIL)) +#define AR_WOW2_PATTERN_EN(x) ((x & 0xff) << 0) +#define AR_WOW2_PATTERN_FOUND_SHIFT 8 +#define AR_WOW2_PATTERN_FOUND(x) (x & (0xff << AR_WOW2_PATTERN_FOUND_SHIFT)) +#define AR_WOW2_PATTERN_FOUND_MASK ((0xff) << AR_WOW2_PATTERN_FOUND_SHIFT) + +#define AR_WOW_STATUS2(x) (x & AR_WOW2_PATTERN_FOUND_MASK) +#define AR_WOW_CLEAR_EVENTS2(x) (x & ~(AR_WOW2_PATTERN_EN(0xff))) + #define AR_WOW_AIFS_CNT(x) (x & 0xff) #define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) #define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 1b8e75c4d2c2..0acd079ba96b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1103,14 +1103,28 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ath_frame_info *fi; struct ieee80211_tx_info *info; + struct ieee80211_vif *vif; struct ath_hw *ah = sc->sc_ah; if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; skb = bf->bf_mpdu; - fi = get_frame_info(skb); info = IEEE80211_SKB_CB(skb); + vif = info->control.vif; + + if (!vif) { + max_power = sc->cur_chan->cur_txpower; + goto out; + } + + if (vif->bss_conf.txpower_type != NL80211_TX_POWER_LIMITED) { + max_power = min_t(u8, sc->cur_chan->cur_txpower, + 2 * vif->bss_conf.txpower); + goto out; + } + + fi = get_frame_info(skb); if (!AR_SREV_9300_20_OR_LATER(ah)) { int txpower = fi->tx_power; @@ -1147,25 +1161,25 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, txpower -= 2; txpower = max(txpower, 0); - max_power = min_t(u8, ah->tx_power[rateidx], txpower); - - /* XXX: clamp minimum TX power at 1 for AR9160 since if - * max_power is set to 0, frames are transmitted at max - * TX power - */ - if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) - max_power = 1; + max_power = min_t(u8, ah->tx_power[rateidx], + 2 * vif->bss_conf.txpower); + max_power = min_t(u8, max_power, txpower); } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) - max_power = min(ah->tx_power_stbc[rateidx], - fi->tx_power); + max_power = min_t(u8, ah->tx_power_stbc[rateidx], + 2 * vif->bss_conf.txpower); else - max_power = min(ah->tx_power[rateidx], fi->tx_power); + max_power = min_t(u8, ah->tx_power[rateidx], + 2 * vif->bss_conf.txpower); + max_power = min(max_power, fi->tx_power); } else { max_power = ah->paprd_training_power; } - - return max_power; +out: + /* XXX: clamp minimum TX power at 1 for AR9160 since if max_power + * is set to 0, frames are transmitted at max TX power + */ + return (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) ? 1 : max_power; } static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 2d5ea21be47e..4bd708c8716c 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -387,11 +387,25 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; + wil_print_connect_params(wil, sme); + if (test_bit(wil_status_fwconnecting, wil->status) || test_bit(wil_status_fwconnected, wil->status)) return -EALREADY; - wil_print_connect_params(wil, sme); + if (sme->ie_len > WMI_MAX_IE_LEN) { + wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len); + return -ERANGE; + } + + rsn_eid = sme->ie ? + cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : + NULL; + + if (sme->privacy && !rsn_eid) { + wil_err(wil, "Missing RSN IE for secure connection\n"); + return -EINVAL; + } bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, @@ -407,17 +421,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = -ENOENT; goto out; } + wil->privacy = sme->privacy; - rsn_eid = sme->ie ? - cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : - NULL; - if (rsn_eid) { - if (sme->ie_len > WMI_MAX_IE_LEN) { - rc = -ERANGE; - wil_err(wil, "IE too large (%td bytes)\n", - sme->ie_len); - goto out; - } + if (wil->privacy) { /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); if (rc) { @@ -450,7 +456,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, bss->capability); goto out; } - if (rsn_eid) { + if (wil->privacy) { conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; @@ -769,7 +775,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); - wil->secure_pcp = info->privacy; + wil->privacy = info->privacy; netif_carrier_on(ndev); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 45c3558ec804..3830cc20d4fa 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -29,6 +29,7 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ +u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */ enum dbg_off_type { doff_u32 = 0, @@ -102,23 +103,30 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) % vring->size; int avail = vring->size - used - 1; char name[10]; + char sidle[10]; /* performance monitoring */ cycles_t now = get_cycles(); uint64_t idle = txdata->idle * 100; uint64_t total = now - txdata->begin; - do_div(idle, total); + if (total != 0) { + do_div(idle, total); + snprintf(sidle, sizeof(sidle), "%3d%%", + (int)idle); + } else { + snprintf(sidle, sizeof(sidle), "N/A"); + } txdata->begin = now; txdata->idle = 0ULL; snprintf(name, sizeof(name), "tx_%2d", i); seq_printf(s, - "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n", - wil->sta[cid].addr, cid, tid, - txdata->agg_wsize, txdata->agg_timeout, - txdata->agg_amsdu ? "+" : "-", - used, avail, (int)idle); + "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", + used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } @@ -549,7 +557,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); - wil_reset(wil); + wil_reset(wil, true); return len; } @@ -618,7 +626,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, struct wil6210_priv *wil = file->private_data; int rc; char *kbuf = kmalloc(len + 1, GFP_KERNEL); - char cmd[8]; + char cmd[9]; int p1, p2, p3; if (!kbuf) @@ -1392,7 +1400,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { - WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), + WIL_FIELD(privacy, S_IRUGO, doff_u32), WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), @@ -1412,6 +1420,8 @@ static const struct dbg_off dbg_statics[] = { {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32}, {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32}, {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32}, + {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh, + doff_u32}, {}, }; diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 4c44a82c34d7..0ea695ff98ad 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,27 +50,19 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, wil_dbg_misc(wil, "%s()\n", __func__); - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) { - tx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); - if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) - tx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); - - rx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); - if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) - rx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); - } else { - rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); - if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN) - rx_itr_val = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - } + tx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) + tx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + + rx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) + rx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 93c5cc16c515..4428345e5a47 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "fw.h" MODULE_FIRMWARE(WIL_FW_NAME); +MODULE_FIRMWARE(WIL_FW2_NAME); /* target operations */ /* register read */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index d4acf93a9a02..157f5ef384e0 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -451,8 +451,6 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) } return -EINVAL; } - /* Mark FW as loaded from host */ - S(RGF_USER_USAGE_6, 1); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index a6f923086f31..28ffc18466c4 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -166,9 +166,16 @@ void wil_unmask_irq(struct wil6210_priv *wil) /* target write operation */ #define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -static -void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) +void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { + wil_dbg_irq(wil, "%s()\n", __func__); + + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + return; + /* Disable and clear tx counter before (re)configuration */ W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); @@ -206,42 +213,8 @@ void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); } -static -void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil) -{ - /* disable, use usec resolution */ - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR); - - wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration); - W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration); - /* start it */ - W(RGF_DMA_ITR_CNT_CRL, - BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK); -} - #undef W -void wil_configure_interrupt_moderation(struct wil6210_priv *wil) -{ - wil_dbg_irq(wil, "%s()\n", __func__); - - /* disable interrupt moderation for monitor - * to get better timestamp precision - */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) - return; - - if (test_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities)) - wil_configure_interrupt_moderation_new(wil); - else { - /* Advanced interrupt moderation is not available before - * Sparrow v2. Will use legacy interrupt moderation - */ - wil_configure_interrupt_moderation_lgc(wil); - } -} - static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -253,7 +226,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) trace_wil6210_irq_rx(isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: RX\n"); return IRQ_NONE; } @@ -266,17 +239,18 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) * action is always the same - should empty the accumulated * packets from the RX ring. */ - if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) { + if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE | + BIT_DMA_EP_RX_ICR_RX_HTRSH))) { wil_dbg_irq(wil, "RX done\n"); - if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) + if (unlikely(isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)) wil_err_ratelimited(wil, "Received \"Rx buffer is in risk of overflow\" interrupt\n"); isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); - if (test_bit(wil_status_reset_done, wil->status)) { - if (test_bit(wil_status_napi_en, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { + if (likely(test_bit(wil_status_napi_en, wil->status))) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); @@ -289,7 +263,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); /* Rx IRQ will be enabled when NAPI processing finished */ @@ -313,19 +287,19 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) trace_wil6210_irq_tx(isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); - if (!isr) { + if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: TX\n"); return IRQ_NONE; } wil6210_mask_irq_tx(wil); - if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { + if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) { wil_dbg_irq(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); - if (test_bit(wil_status_reset_done, wil->status)) { + if (likely(test_bit(wil_status_reset_done, wil->status))) { wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_tx); @@ -334,7 +308,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) } } - if (isr) + if (unlikely(isr)) wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); /* Tx IRQ will be enabled when NAPI processing finished */ @@ -523,11 +497,11 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) /** * pseudo_cause is Clear-On-Read, no need to ACK */ - if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) + if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))) return IRQ_NONE; /* FIXME: IRQ mask debug */ - if (wil6210_debug_irq_mask(wil, pseudo_cause)) + if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause))) return IRQ_NONE; trace_wil6210_irq_pseudo(pseudo_cause); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b04e0afdcb21..db74e811f5c4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -29,10 +29,6 @@ bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); -static bool no_fw_load = true; -module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); - /* if not set via modparam, will be set to default value of 1/8 of * rx ring size during init flow */ @@ -520,8 +516,6 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - bool is_reset_v2 = test_bit(hw_capability_reset_v2, - wil->hw_capabilities); wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); @@ -532,82 +526,67 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); + /* clear all boot loader "ready" bits */ + W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_reset_v2) { - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); - /* XTAL stabilization should take about 3ms */ - usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); - if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { - wil_err(wil, "Xtal stabilization timeout\n" - "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); - return -ETIME; - } - /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); - /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + /* XTAL stabilization should take about 3ms */ + usleep_range(5000, 7000); + x = R(RGF_CAF_PLL_LOCK_STATUS); + if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { + wil_err(wil, "Xtal stabilization timeout\n" + "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); + return -ETIME; } + /* switch 10k to XTAL*/ + C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + /* 40 MHz */ + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, - is_reset_v2 ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - } + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_reset_v2) { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - /* reset A2 PCIE AHB */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } else { - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ - /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. typical time is 200..250 msec */ + /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_HW_MACHINE_STATE); + x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, hw_state 0x%08x\n", + wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } - } while (x != HW_MACHINE_BOOT_DONE); - - if (!is_reset_v2) - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); + } while (!(x & BIT_BL_READY)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + /* enable fix for HW bug related to the SA/DA swap in AP Rx */ + S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } -#undef R -#undef W -#undef S -#undef C - void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { le32_to_cpus(&r->base); @@ -617,6 +596,32 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) le32_to_cpus(&r->head); } +static int wil_get_bl_info(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct RGF_BL bl; + + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); + le32_to_cpus(&bl.ready); + le32_to_cpus(&bl.version); + le32_to_cpus(&bl.rf_type); + le32_to_cpus(&bl.baseband_type); + + if (!is_valid_ether_addr(bl.mac_address)) { + wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + return -EINVAL; + } + + ether_addr_copy(ndev->perm_addr, bl.mac_address); + if (!is_valid_ether_addr(ndev->dev_addr)) + ether_addr_copy(ndev->dev_addr, bl.mac_address); + wil_info(wil, + "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + + return 0; +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -637,7 +642,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) * After calling this routine, you're expected to reload * the firmware. */ -int wil_reset(struct wil6210_priv *wil) +int wil_reset(struct wil6210_priv *wil, bool load_fw) { int rc; @@ -675,30 +680,36 @@ int wil_reset(struct wil6210_priv *wil) if (rc) return rc; - if (!no_fw_load) { - wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); + rc = wil_get_bl_info(wil); + if (rc) + return rc; + + if (load_fw) { + wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME, + WIL_FW2_NAME); + wil_halt_cpu(wil); /* Loading f/w from the file */ rc = wil_request_firmware(wil, WIL_FW_NAME); if (rc) return rc; + rc = wil_request_firmware(wil, WIL_FW2_NAME); + if (rc) + return rc; - /* clear any interrupts which on-card-firmware may have set */ + /* Mark FW as loaded from host */ + S(RGF_USER_USAGE_6, 1); + + /* clear any interrupts which on-card-firmware + * may have set + */ wil6210_clear_irq(wil); - { /* CAF_ICR - clear and mask */ - u32 a = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, ICR); - u32 m = HOSTADDR(RGF_CAF_ICR) + - offsetof(struct RGF_ICR, IMV); - u32 icr = ioread32(wil->csr + a); - - iowrite32(icr, wil->csr + a); /* W1C */ - iowrite32(~0, wil->csr + m); - wmb(); /* wait for completion */ - } + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_release_cpu(wil); - } else { - wil_info(wil, "Use firmware from on-card flash\n"); } /* init after reset */ @@ -706,15 +717,22 @@ int wil_reset(struct wil6210_priv *wil) reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); - wil_configure_interrupt_moderation(wil); - wil_unmask_irq(wil); + if (load_fw) { + wil_configure_interrupt_moderation(wil); + wil_unmask_irq(wil); - /* we just started MAC, wait for FW ready */ - rc = wil_wait_for_fw_ready(wil); + /* we just started MAC, wait for FW ready */ + rc = wil_wait_for_fw_ready(wil); + } return rc; } +#undef R +#undef W +#undef S +#undef C + void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); @@ -730,7 +748,7 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); - rc = wil_reset(wil); + rc = wil_reset(wil, true); if (rc) return rc; @@ -837,7 +855,7 @@ int __wil_down(struct wil6210_priv *wil) if (!iter) wil_err(wil, "timeout waiting for idle FW/HW\n"); - wil_rx_fini(wil); + wil_reset(wil, false); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 3dd26709ccb2..25343cffe229 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -39,18 +39,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) bitmap_zero(wil->hw_capabilities, hw_capability_last); switch (rev_id) { - case JTAG_DEV_ID_MARLON_B0: - wil->hw_name = "Marlon B0"; - wil->hw_version = HW_VER_MARLON_B0; - break; - case JTAG_DEV_ID_SPARROW_A0: - wil->hw_name = "Sparrow A0"; - wil->hw_version = HW_VER_SPARROW_A0; - break; - case JTAG_DEV_ID_SPARROW_A1: - wil->hw_name = "Sparrow A1"; - wil->hw_version = HW_VER_SPARROW_A1; - break; case JTAG_DEV_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; wil->hw_version = HW_VER_SPARROW_B0; @@ -62,13 +50,6 @@ void wil_set_capabilities(struct wil6210_priv *wil) } wil_info(wil, "Board hardware is %s\n", wil->hw_name); - - if (wil->hw_version >= HW_VER_SPARROW_A0) - set_bit(hw_capability_reset_v2, wil->hw_capabilities); - - if (wil->hw_version >= HW_VER_SPARROW_B0) - set_bit(hw_capability_advanced_itr_moderation, - wil->hw_capabilities); } void wil_disable_irq(struct wil6210_priv *wil) @@ -150,7 +131,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); - rc = wil_reset(wil); + rc = wil_reset(wil, false); mutex_unlock(&wil->mutex); if (debug_fw) rc = 0; @@ -305,7 +286,6 @@ static void wil_pcie_remove(struct pci_dev *pdev) } static const struct pci_device_id wil6210_pcie_ids[] = { - { PCI_DEVICE(0x1ae9, 0x0301) }, { PCI_DEVICE(0x1ae9, 0x0310) }, { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { /* end: all zeroes */ }, diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 8439f65db259..7f2f560b8638 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -53,34 +53,38 @@ static inline int wil_vring_is_full(struct vring *vring) return wil_vring_next_tail(vring) == vring->swhead; } -/* - * Available space in Tx Vring - */ -static inline int wil_vring_avail_tx(struct vring *vring) +/* Used space in Tx Vring */ +static inline int wil_vring_used_tx(struct vring *vring) { u32 swhead = vring->swhead; u32 swtail = vring->swtail; - int used = (vring->size + swhead - swtail) % vring->size; + return (vring->size + swhead - swtail) % vring->size; +} - return vring->size - used - 1; +/* Available space in Tx Vring */ +static inline int wil_vring_avail_tx(struct vring *vring) +{ + return vring->size - wil_vring_used_tx(vring) - 1; } -/** - * wil_vring_wmark_low - low watermark for available descriptor space - */ +/* wil_vring_wmark_low - low watermark for available descriptor space */ static inline int wil_vring_wmark_low(struct vring *vring) { return vring->size/8; } -/** - * wil_vring_wmark_high - high watermark for available descriptor space - */ +/* wil_vring_wmark_high - high watermark for available descriptor space */ static inline int wil_vring_wmark_high(struct vring *vring) { return vring->size/4; } +/* wil_val_in_range - check if value in [min,max) */ +static inline bool wil_val_in_range(int val, int min, int max) +{ + return val >= min && val < max; +} + static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) { struct device *dev = wil_to_dev(wil); @@ -98,8 +102,7 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) vring->va = NULL; return -ENOMEM; } - /* - * vring->va should be aligned on its size rounded up to power of 2 + /* vring->va should be aligned on its size rounded up to power of 2 * This is granted by the dma_alloc_coherent */ vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); @@ -346,27 +349,6 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, } } -/* - * Fast swap in place between 2 registers - */ -static void wil_swap_u16(u16 *a, u16 *b) -{ - *a ^= *b; - *b ^= *a; - *a ^= *b; -} - -static void wil_swap_ethaddr(void *data) -{ - struct ethhdr *eth = data; - u16 *s = (u16 *)eth->h_source; - u16 *d = (u16 *)eth->h_dest; - - wil_swap_u16(s++, d++); - wil_swap_u16(s++, d++); - wil_swap_u16(s, d); -} - /** * reap 1 frame from @swhead * @@ -386,17 +368,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, unsigned int sz = mtu_max + ETH_HLEN; u16 dmalen; u8 ftype; - u8 ds_bits; int cid; struct wil_net_stats *stats; BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); - if (wil_vring_is_empty(vring)) + if (unlikely(wil_vring_is_empty(vring))) return NULL; _d = &vring->va[vring->swhead].rx; - if (!(_d->dma.status & RX_DMA_STATUS_DU)) { + if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { /* it is not error, we just reached end of Rx done area */ return NULL; } @@ -416,7 +397,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - if (dmalen > sz) { + if (unlikely(dmalen > sz)) { wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); kfree_skb(skb); return NULL; @@ -445,14 +426,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * in Rx descriptor. If type is not data, it is 802.11 frame as is */ ftype = wil_rxdesc_ftype(d) << 2; - if (ftype != IEEE80211_FTYPE_DATA) { + if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); /* TODO: process it */ kfree_skb(skb); return NULL; } - if (skb->len < ETH_HLEN) { + if (unlikely(skb->len < ETH_HLEN)) { wil_err(wil, "Short frame, len = %d\n", skb->len); /* TODO: process it (i.e. BAR) */ kfree_skb(skb); @@ -463,9 +444,9 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * and in case of error drop the packet * higher stack layers will handle retransmission (if required) */ - if (d->dma.status & RX_DMA_STATUS_L4I) { + if (likely(d->dma.status & RX_DMA_STATUS_L4I)) { /* L4 protocol identified, csum calculated */ - if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) + if (likely((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)) skb->ip_summed = CHECKSUM_UNNECESSARY; /* If HW reports bad checksum, let IP stack re-check it * For example, HW don't understand Microsoft IP stack that @@ -474,15 +455,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ } - ds_bits = wil_rxdesc_ds_bits(d); - if (ds_bits == 1) { - /* - * HW bug - in ToDS mode, i.e. Rx on AP side, - * addresses get swapped - */ - wil_swap_ethaddr(skb->data); - } - return skb; } @@ -503,7 +475,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) (next_tail != v->swhead) && (count-- > 0); v->swtail = next_tail) { rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); - if (rc) { + if (unlikely(rc)) { wil_err(wil, "Error %d in wil_rx_refill[%d]\n", rc, v->swtail); break; @@ -565,7 +537,7 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) struct vring *v = &wil->vring_rx; struct sk_buff *skb; - if (!v->va) { + if (unlikely(!v->va)) { wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); return; } @@ -952,13 +924,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; uint i = swhead; dma_addr_t pa; + int used; wil_dbg_txrx(wil, "%s()\n", __func__); if (unlikely(!txdata->enabled)) return -EINVAL; - if (avail < 1 + nr_frags) { + if (unlikely(avail < 1 + nr_frags)) { wil_err_ratelimited(wil, "Tx ring[%2d] full. No space for %d fragments\n", vring_index, 1 + nr_frags); @@ -979,7 +952,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* 1-st segment */ wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ - if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { + if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; @@ -1027,8 +1000,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - if (wil_vring_is_empty(vring)) /* performance monitoring */ + /* performance monitoring */ + used = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used, used + nr_frags + 1)) { txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + vring_index, used, used + nr_frags + 1); + } /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); @@ -1082,18 +1061,18 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) int rc; wil_dbg_txrx(wil, "%s()\n", __func__); - if (!test_bit(wil_status_fwready, wil->status)) { + if (unlikely(!test_bit(wil_status_fwready, wil->status))) { if (!pr_once_fw) { wil_err(wil, "FW not ready\n"); pr_once_fw = true; } goto drop; } - if (!test_bit(wil_status_fwconnected, wil->status)) { + if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { wil_err(wil, "FW not connected\n"); goto drop; } - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } @@ -1109,7 +1088,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) else vring = wil_tx_bcast(wil, skb); } - if (!vring) { + if (unlikely(!vring)) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } @@ -1117,7 +1096,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) rc = wil_tx_vring(wil, vring, skb); /* do we still have enough room in the vring? */ - if (wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring)) { + if (unlikely(wil_vring_avail_tx(vring) < wil_vring_wmark_low(vring))) { netif_tx_stop_all_queues(wil_to_ndev(wil)); wil_dbg_txrx(wil, "netif_tx_stop : ring full\n"); } @@ -1172,19 +1151,23 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) int cid = wil->vring2cid_tid[ringid][0]; struct wil_net_stats *stats = &wil->sta[cid].stats; volatile struct vring_tx_desc *_d; + int used_before_complete; + int used_new; - if (!vring->va) { + if (unlikely(!vring->va)) { wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); return 0; } - if (!txdata->enabled) { + if (unlikely(!txdata->enabled)) { wil_info(wil, "Tx irq[%d]: vring disabled\n", ringid); return 0; } wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); + used_before_complete = wil_vring_used_tx(vring); + while (!wil_vring_is_empty(vring)) { int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; @@ -1196,7 +1179,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) /* TODO: check we are not past head */ _d = &vring->va[lf].tx; - if (!(_d->dma.status & TX_DMA_STATUS_DU)) + if (unlikely(!(_d->dma.status & TX_DMA_STATUS_DU))) break; new_swtail = (lf + 1) % vring->size; @@ -1224,7 +1207,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) wil_txdesc_unmap(dev, d, ctx); if (skb) { - if (d->dma.error == 0) { + if (likely(d->dma.error == 0)) { ndev->stats.tx_packets++; stats->tx_packets++; ndev->stats.tx_bytes += skb->len; @@ -1246,8 +1229,12 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) } } - if (wil_vring_is_empty(vring)) { /* performance monitoring */ - wil_dbg_txrx(wil, "Ring[%2d] empty\n", ringid); + /* performance monitoring */ + used_new = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used_new, used_before_complete)) { + wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n", + ringid, used_before_complete, used_new); txdata->last_idle = get_cycles(); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 94611568fc9a..b6e65c37d410 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -27,9 +27,11 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; +extern u32 vring_idle_trsh; #define WIL_NAME "wil6210" -#define WIL_FW_NAME "wil6210.fw" +#define WIL_FW_NAME "wil6210.fw" /* code */ +#define WIL_FW2_NAME "wil6210.board" /* board & radio parameters */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ @@ -120,6 +122,16 @@ struct RGF_ICR { u32 IMC; /* Mask Clear, write 1 to clear */ } __packed; +struct RGF_BL { + u32 ready; /* 0x880A3C bit [0] */ +#define BIT_BL_READY BIT(0) + u32 version; /* 0x880A40 version of the BL struct */ + u32 rf_type; /* 0x880A44 ID of the connected RF */ + u32 baseband_type; /* 0x880A48 ID of the baseband */ + u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ + u8 pad[2]; +} __packed; + /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) @@ -130,6 +142,7 @@ struct RGF_ICR { #define RGF_USER_MAC_CPU_0 (0x8801fc) #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) +#define RGF_USER_BL (0x880A3C) /* Boot Loader */ #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_CLKS_CTL_0 (0x880abc) #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ @@ -169,6 +182,13 @@ struct RGF_ICR { #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +/* Offload control (Sparrow B0+) */ +#define RGF_DMA_OFUL_NID_0 (0x881cd4) + #define BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN BIT(0) + #define BIT_DMA_OFUL_NID_0_TX_EXT_TR_EN BIT(1) + #define BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC BIT(2) + #define BIT_DMA_OFUL_NID_0_TX_EXT_A3_SRC BIT(3) + /* New (sparrow v2+) interrupt moderation control */ #define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40) #define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34) @@ -229,16 +249,10 @@ struct RGF_ICR { #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) #define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ - #define JTAG_DEV_ID_MARLON_B0 (0x0612072f) - #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f) - #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f) #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) enum { HW_VER_UNKNOWN, - HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */ - HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */ - HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */ HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ }; @@ -482,8 +496,6 @@ enum { }; enum { - hw_capability_reset_v2 = 0, - hw_capability_advanced_itr_moderation = 1, hw_capability_last }; @@ -528,7 +540,7 @@ struct wil6210_priv { wait_queue_head_t wq; /* for all wait_event() use */ /* profile */ u32 monitor_flags; - u32 secure_pcp; /* create secure PCP? */ + u32 privacy; /* secure connection? */ int sinfo_gen; /* interrupt moderation */ u32 tx_max_burst_duration; @@ -658,7 +670,7 @@ int wil_if_add(struct wil6210_priv *wil); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); -int wil_reset(struct wil6210_priv *wil); +int wil_reset(struct wil6210_priv *wil, bool no_fw); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); int wil_up(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 0f3e4334c8e3..021313524913 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -281,7 +281,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) /*=== Event handlers ===*/ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wmi_ready_event *evt = d; @@ -290,11 +289,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version, evt->mac, wil->n_mids); - - if (!is_valid_ether_addr(ndev->dev_addr)) { - memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); - memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); - } + /* ignore MAC address, we already have it from the boot loader */ snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), "%d", wil->fw_version); } @@ -879,7 +874,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) struct wmi_pcp_started_event evt; } __packed reply; - if (!wil->secure_pcp) + if (!wil->privacy) cmd.disable_sec = 1; if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) || |