From a7595a820b07db9ac0d8f479ff62002bdd32a05a Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 20 Mar 2017 20:52:46 +0530 Subject: [PATCH 001/201] ath10k: fix NAPI enable/disable symmetry for AHB interface Move NAPI enable to 'ath10k_ahb_hif_start' from 'ath10k_ahb_hif_power_up'. This is to maintain the symmetry of calling napi_enable() from ath10k_ahb_hif_start() so that it matches with napi_disable() being called from ath10k_pci_hif_stop(). This change is based on the crash fix from Kalle for PCI interface in commit 1427228d5869 ("ath10k: fix napi crash during rmmod when probe firmware fails"). Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ahb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 45226dbee5ce2..da770af830369 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -640,6 +640,7 @@ static int ath10k_ahb_hif_start(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n"); + napi_enable(&ar->napi); ath10k_ce_enable_interrupts(ar); ath10k_pci_enable_legacy_irq(ar); @@ -692,7 +693,6 @@ static int ath10k_ahb_hif_power_up(struct ath10k *ar) ath10k_err(ar, "could not wake up target CPU: %d\n", ret); goto err_ce_deinit; } - napi_enable(&ar->napi); return 0; From ebeb36670ecac36c179b5fb5d5c88ff03ba191ec Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Mar 2017 13:44:20 +0100 Subject: [PATCH 002/201] ath9k_htc: fix NULL-deref at probe Make sure to check the number of endpoints to avoid dereferencing a NULL-pointer or accessing memory beyond the endpoint array should a malicious device lack the expected endpoints. Fixes: 36bcce430657 ("ath9k_htc: Handle storage devices") Cc: stable # 2.6.39+ Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hif_usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 05dd056cab6ea..12aa8abbcba40 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1220,6 +1220,9 @@ static int send_eject_command(struct usb_interface *interface) u8 bulk_out_ep; int r; + if (iface_desc->desc.bNumEndpoints < 2) + return -ENODEV; + /* Find bulk out endpoint */ for (r = 1; r >= 0; r--) { endpoint = &iface_desc->endpoint[r].desc; From fefcd11535abc4cb45d1572afc2351114572493e Mon Sep 17 00:00:00 2001 From: Venkateswara Rao Naralasetty Date: Fri, 24 Mar 2017 13:27:28 +0530 Subject: [PATCH 003/201] ath10k: fix station nss computation If station advertises diffferent NSS capabilities in Rx_mcs set of HT and VHT IEs in assoc req, the current NSS computation logic configures the NSS support only based on Rx_mcs set of HT capabilities in the driver. This is configuring the station NSS capabilities incorreclty in the target. For example, if station advertise Rx_mcs set as 2 spatial streams in HT capabilities and 1 spatial streams in VHT capabilities in assoc request, as per current logic we are calculating nss from HT capabilities and the driver sets peer_num_spatial_streams as 2 for the station which is configured in VHT 1*1. This patchs fix this issue by calculating the nss from VHT cap if station supports vht. Signed-off-by: Venkateswara Rao Naralasetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 968b1d421225b..3ca713e09ce9f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2451,6 +2451,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, enum nl80211_band band; const u16 *vht_mcs_mask; u8 ampdu_factor; + u8 max_nss, vht_mcs; + int i; if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) return; @@ -2489,6 +2491,18 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, if (sta->bandwidth == IEEE80211_STA_RX_BW_160) arg->peer_flags |= ar->wmi.peer_flags->bw160; + /* Calculate peer NSS capability from VHT capabilities if STA + * supports VHT. + */ + for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) { + vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >> + (2 * i) & 3; + + if ((vht_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) && + vht_mcs_mask[i]) + max_nss = i + 1; + } + arg->peer_num_spatial_streams = min(sta->rx_nss, max_nss); arg->peer_vht_rates.rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest); arg->peer_vht_rates.rx_mcs_set = From d94475c2f95c8fbc6871aaf2df3fd093c329dde8 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 31 Mar 2017 17:28:41 +0530 Subject: [PATCH 004/201] ath10k: cancel coverage class work during stop and restart It seems set_coverage_class_work is not cancelled anywhere, though I could not find a crash/warning with this existing design, its safer to cancel it during stop() and also before restarting the hardware. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 7 +++++++ drivers/net/wireless/ath/ath10k/mac.c | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f450ebbb28d53..85a14e2b3d04b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1627,6 +1627,13 @@ static void ath10k_core_restart(struct work_struct *work) wake_up(&ar->wmi.tx_credits_wq); wake_up(&ar->peer_mapping_wq); + /* TODO: We can have one instance of cancelling coverage_class_work by + * moving it to ath10k_halt(), so that both stop() and restart() would + * call that but it takes conf_mutex() and if we call cancel_work_sync() + * with conf_mutex it will deadlock. + */ + cancel_work_sync(&ar->set_coverage_class_work); + mutex_lock(&ar->conf_mutex); switch (ar->state) { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3ca713e09ce9f..ddabec8022f46 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4717,6 +4717,7 @@ static void ath10k_stop(struct ieee80211_hw *hw) } mutex_unlock(&ar->conf_mutex); + cancel_work_sync(&ar->set_coverage_class_work); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->restart_work); } From 03e463a4197a05f196b1b9e9bb3b66fecbe50889 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 31 Mar 2017 17:29:26 +0530 Subject: [PATCH 005/201] ath10k: enable a HTC debug message during insufficient tx credits Add an ath10k HTC debug message when insufficient tx credits are available to send the WMI commands. This is very useful in debugging issues like 'tx credit starvation' that could possibly happen with multiclient setup with constant roaming Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 9f6a915f91bfe..f56f60462b33f 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -119,6 +119,9 @@ int ath10k_htc_send(struct ath10k_htc *htc, credits = DIV_ROUND_UP(skb->len, htc->target_credit_size); spin_lock_bh(&htc->tx_lock); if (ep->tx_credits < credits) { + ath10k_dbg(ar, ATH10K_DBG_HTC, + "htc insufficient credits ep %d required %d available %d\n", + eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); ret = -EAGAIN; goto err_pull; From fb7fa766a8cf9dede60f71ba87241f37bd98cabe Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 31 Mar 2017 17:30:44 +0530 Subject: [PATCH 006/201] ath10k: remove obselete Copy Engine comments Remove obselete Copy Engine comments referring to the function ath10k_ce_sendlist_send as this function was removed long time back by the commit 2e761b5a5222 ("ath10k: remove ce_sendlist_send"). Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 4045657e0a6ec..9ac0a73a3a9f8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -261,8 +261,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, } /* - * Guts of ath10k_ce_send, used by both ath10k_ce_send and - * ath10k_ce_sendlist_send. + * Guts of ath10k_ce_send. * The caller takes responsibility for any needed locking. */ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, From e871fb6396f7251ae4a90c20be38015c8b20e502 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Fri, 31 Mar 2017 17:39:40 +0530 Subject: [PATCH 007/201] ath10k: fix the Transmit Power Control stats display format This patch helps to fix TPC stats to display the stats properly. Here cosmetic change has been done to print the TPC stats for all the cases 1.CDD 2.STBC 3.TXBF Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 00b424d99126a..1339cc383797f 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1816,7 +1816,7 @@ static void ath10k_tpc_stats_fill(struct ath10k *ar, tpc_stats->num_tx_chain, tpc_stats->rate_max); - for (j = 0; j < tpc_stats->num_tx_chain ; j++) { + for (j = 0; j < WMI_TPC_FLAG; j++) { switch (j) { case WMI_TPC_TABLE_TYPE_CDD: if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { From d6dfe25c8bb200027dfc5c793cbec81c9af6dd2e Mon Sep 17 00:00:00 2001 From: Marcin Rokicki Date: Mon, 20 Feb 2017 14:39:57 +0100 Subject: [PATCH 008/201] ath10k: fix block comments style Fix output from checkpatch.pl like: Block comments use a trailing */ on a separate lin Signed-off-by: Marcin Rokicki Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 9 +++-- drivers/net/wireless/ath/ath10k/debug.c | 3 +- drivers/net/wireless/ath/ath10k/htc.c | 3 +- drivers/net/wireless/ath/ath10k/htt_rx.c | 9 +++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 6 ++-- drivers/net/wireless/ath/ath10k/mac.c | 43 ++++++++++++++--------- drivers/net/wireless/ath/ath10k/pci.c | 12 ++++--- drivers/net/wireless/ath/ath10k/thermal.c | 3 +- drivers/net/wireless/ath/ath10k/txrx.c | 3 +- drivers/net/wireless/ath/ath10k/wmi.c | 16 +++++---- 10 files changed, 69 insertions(+), 38 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 85a14e2b3d04b..1b4c08b5eaa9d 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1645,7 +1645,8 @@ static void ath10k_core_restart(struct work_struct *work) break; case ATH10K_STATE_OFF: /* this can happen if driver is being unloaded - * or if the crash happens during FW probing */ + * or if the crash happens during FW probing + */ ath10k_warn(ar, "cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: @@ -2173,7 +2174,8 @@ EXPORT_SYMBOL(ath10k_core_stop); /* mac80211 manages fw/hw initialization through start/stop hooks. However in * order to know what hw capabilities should be advertised to mac80211 it is * necessary to load the firmware (and tear it down immediately since start - * hook will try to init it again) before registering */ + * hook will try to init it again) before registering + */ static int ath10k_core_probe_fw(struct ath10k *ar) { struct bmi_target_info target_info; @@ -2367,7 +2369,8 @@ void ath10k_core_unregister(struct ath10k *ar) /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be - * unhappy about callback failures. */ + * unhappy about callback failures. + */ ath10k_mac_unregister(ar); ath10k_testmode_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 1339cc383797f..8cda518d1150c 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1982,7 +1982,8 @@ void ath10k_debug_stop(struct ath10k *ar) /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid - * warning from del_timer(). */ + * warning from del_timer(). + */ if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f56f60462b33f..b7669b2e94aae 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -422,7 +422,8 @@ static void ath10k_htc_control_rx_complete(struct ath10k *ar, struct sk_buff *skb) { /* This is unexpected. FW is not supposed to send regular rx on this - * endpoint. */ + * endpoint. + */ ath10k_warn(ar, "unexpected htc rx\n"); kfree_skb(skb); } diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 02a3fc81fbe3b..3448a3ce59198 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -177,7 +177,8 @@ 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 average 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); @@ -304,7 +305,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, rx_desc = (struct htt_rx_desc *)msdu->data; /* FIXME: we must report msdu payload since this is what caller - * expects now */ + * expects now + */ skb_put(msdu, offsetof(struct htt_rx_desc, msdu_payload)); skb_pull(msdu, offsetof(struct htt_rx_desc, msdu_payload)); @@ -639,7 +641,8 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, case HTT_RX_VHT: case HTT_RX_VHT_WITH_TXBF: /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3 - TODO check this */ + * TODO check this + */ bw = info2 & 3; sgi = info3 & 1; group_id = (info2 >> 4) & 0x3F; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 86b427f5e2bcb..685faac1368fd 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -526,7 +526,8 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) memset(req, 0, sizeof(*req)); /* currently we support only max 8 bit masks so no need to worry - * about endian support */ + * about endian support + */ req->upload_types[0] = mask; req->reset_types[0] = mask; req->stat_type = HTT_STATS_REQ_CFG_STAT_TYPE_INVALID; @@ -1008,7 +1009,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, * There is simply no point in pushing HTT TX_FRM through HTC tx path * as it's a waste of resources. By bypassing HTC it is possible to * avoid extra memory allocations, compress data structures and thus - * improve performance. */ + * improve performance. + */ txbuf->htc_hdr.eid = htt->eid; txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) + diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ddabec8022f46..9dc06832b7f10 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -457,7 +457,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, for (;;) { /* since ath10k_install_key we can't hold data_lock all the - * time, so we try to remove the keys incrementally */ + * time, so we try to remove the keys incrementally + */ spin_lock_bh(&ar->data_lock); i = 0; list_for_each_entry(peer, &ar->peers, list) { @@ -609,7 +610,8 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity) case 2: case 3: /* Our lower layer calculations limit our precision to - 1 microsecond */ + * 1 microsecond + */ return 1; case 4: return 2; @@ -978,7 +980,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) arg.channel.band_center_freq2 = chandef->center_freq2; /* TODO setup this dynamically, what in case we - don't have any vifs? */ + * don't have any vifs? + */ arg.channel.mode = chan_to_phymode(chandef); arg.channel.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); @@ -2373,9 +2376,10 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar, } /* TODO setup this based on STA listen interval and - beacon interval. Currently we don't know - sta->listen_interval - mac80211 patch required. - Currently use 10 seconds */ + * beacon interval. Currently we don't know + * sta->listen_interval - mac80211 patch required. + * Currently use 10 seconds + */ ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10); @@ -2480,7 +2484,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, /* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to * zero in VHT IE. Using it would result in degraded throughput. * arg->peer_max_mpdu at this point contains HT max_mpdu so keep - * it if VHT max_mpdu is smaller. */ + * it if VHT max_mpdu is smaller. + */ arg->peer_max_mpdu = max(arg->peer_max_mpdu, (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + ampdu_factor)) - 1); @@ -2793,7 +2798,8 @@ 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. */ + * before calling ath10k_setup_peer_smps() which might sleep. + */ ht_cap = ap_sta->ht_cap; vht_cap = ap_sta->vht_cap; @@ -3064,7 +3070,8 @@ static int ath10k_update_channel_list(struct ath10k *ar) /* FIXME: why use only legacy modes, why not any * HT/VHT modes? Would that even make any - * difference? */ + * difference? + */ if (channel->band == NL80211_BAND_2GHZ) ch->mode = MODE_11G; else @@ -3128,7 +3135,8 @@ static void ath10k_regd_update(struct ath10k *ar) } /* Target allows setting up per-band regdomain but ath_common provides - * a combined one only */ + * a combined one only + */ ret = ath10k_wmi_pdev_set_regdomain(ar, regpair->reg_domain, regpair->reg_domain, /* 2ghz */ @@ -3677,7 +3685,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) * never transmitted. We delete the peer upon tx completion. * It is unlikely that a peer for offchannel tx will already be * present. However it may be in some rare cases so account for that. - * Otherwise we might remove a legitimate peer and break stuff. */ + * Otherwise we might remove a legitimate peer and break stuff. + */ for (;;) { skb = skb_dequeue(&ar->offchan_tx_queue); @@ -5717,7 +5726,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } /* the peer should not disappear in mid-way (unless FW goes awry) since - * we already hold conf_mutex. we just make sure its there now. */ + * we already hold conf_mutex. we just make sure its there now. + */ spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr); spin_unlock_bh(&ar->data_lock); @@ -5729,8 +5739,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = -EOPNOTSUPP; goto exit; } else { - /* if the peer doesn't exist there is no key to disable - * anymore */ + /* if the peer doesn't exist there is no key to disable anymore */ goto exit; } } @@ -6589,7 +6598,8 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, long time_left; /* mac80211 doesn't care if we really xmit queued frames or not - * we'll collect those frames either way if we stop/delete vdevs */ + * we'll collect those frames either way if we stop/delete vdevs + */ if (drop) return; @@ -6640,7 +6650,8 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); /* If device failed to restart it will be in a different state, e.g. - * ATH10K_STATE_WEDGED */ + * ATH10K_STATE_WEDGED + */ if (ar->state == ATH10K_STATE_RESTARTED) { ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 52896c20ca4e5..b20b66d9d7bcf 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -720,14 +720,16 @@ void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) { /* IMPORTANT: INTR_CLR register has to be set after * INTR_ENABLE is set to 0, otherwise interrupt can not be - * really cleared. */ + * really cleared. + */ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 0); ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS, PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); /* IMPORTANT: this extra read transaction is required to - * flush the posted write buffer. */ + * flush the posted write buffer. + */ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS); } @@ -739,7 +741,8 @@ void ath10k_pci_enable_legacy_irq(struct ath10k *ar) PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); /* IMPORTANT: this extra read transaction is required to - * flush the posted write buffer. */ + * flush the posted write buffer. + */ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS); } @@ -2908,7 +2911,8 @@ static int ath10k_pci_init_irq(struct ath10k *ar) * host won't know when target writes BAR to CORE_CTRL. * This write might get lost if target has NOT written BAR. * For now, fix the race by repeating the write in below - * synchronization checking. */ + * synchronization checking. + */ ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 0a47269be289d..f719d7d43cb0d 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -191,7 +191,8 @@ int ath10k_thermal_register(struct ath10k *ar) return 0; /* Avoid linking error on devm_hwmon_device_register_with_groups, I - * guess linux/hwmon.h is missing proper stubs. */ + * guess linux/hwmon.h is missing proper stubs. + */ if (!IS_REACHABLE(CONFIG_HWMON)) return 0; diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 9852c5d51139e..d4986f626c35c 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -34,7 +34,8 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb) /* If the original wait_for_completion() timed out before * {data,mgmt}_tx_completed() was called then we could complete * offchan_tx_completed for a different skb. Prevent this by using - * offchan_tx_skb. */ + * offchan_tx_skb. + */ spin_lock_bh(&ar->data_lock); if (ar->offchan_tx_skb != skb) { ath10k_warn(ar, "completed old offchannel frame\n"); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4e60caec7ab41..6afc8d27f0d51 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3210,7 +3210,8 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1; /* if next SWBA has no tim_changed the tim_bitmap is garbage. - * we must copy the bitmap upon change and reuse it later */ + * we must copy the bitmap upon change and reuse it later + */ if (__le32_to_cpu(tim_info->tim_changed)) { int i; @@ -3529,7 +3530,8 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) * before telling mac80211 to decrement CSA counter * * Once CSA counter is completed stop sending beacons until - * actual channel switch is done */ + * actual channel switch is done + */ if (arvif->vif->csa_active && ieee80211_csa_is_complete(arvif->vif)) { ieee80211_csa_finish(arvif->vif); @@ -3691,7 +3693,8 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, ATH10K_DFS_STAT_INC(ar, radar_detected); /* Control radar events reporting in debugfs file - dfs_block_radar_events */ + * dfs_block_radar_events + */ if (ar->dfs_block_radar_events) { ath10k_info(ar, "DFS Radar detected, but ignored as requested\n"); return; @@ -4769,9 +4772,10 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) num_units = ar->max_num_peers + 1; } else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) { /* number of units to allocate is number of - * peers, 1 extra for self peer on target */ - /* this needs to be tied, host and target - * can get out of sync */ + * peers, 1 extra for self peer on target + * this needs to be tied, host and target + * can get out of sync + */ num_units = ar->max_num_peers + 1; } else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) { num_units = ar->max_num_vdevs + 1; From 53c8d48bb72388e22110e5ef1f52dfc3fac6d97f Mon Sep 17 00:00:00 2001 From: Marcin Rokicki Date: Mon, 20 Feb 2017 14:40:27 +0100 Subject: [PATCH 009/201] ath10k: use octal permission representation Fix output from checkpatch.pl like: Symbolic permissions 'S_IRUSR' are not preferred. Consider using octal permissions '0400'. Signed-off-by: Marcin Rokicki Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 88 +++++++++---------- drivers/net/wireless/ath/ath10k/debugfs_sta.c | 9 +- drivers/net/wireless/ath/ath10k/spectral.c | 6 +- drivers/net/wireless/ath/ath10k/thermal.c | 2 +- 4 files changed, 50 insertions(+), 55 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8cda518d1150c..4cd2a0fd49d6e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2444,86 +2444,82 @@ int ath10k_debug_register(struct ath10k *ar) init_completion(&ar->debug.tpc_complete); init_completion(&ar->debug.fw_stats_complete); - debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, + debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar, &fops_fw_stats); - debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy, - ar, &fops_fw_reset_stats); + debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar, + &fops_fw_reset_stats); - debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, + debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar, &fops_wmi_services); - debugfs_create_file("simulate_fw_crash", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_simulate_fw_crash); + debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar, + &fops_simulate_fw_crash); - debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy, - ar, &fops_fw_crash_dump); + debugfs_create_file("fw_crash_dump", 0400, ar->debug.debugfs_phy, ar, + &fops_fw_crash_dump); - debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_reg_addr); + debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar, + &fops_reg_addr); - debugfs_create_file("reg_value", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_reg_value); + debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar, + &fops_reg_value); - debugfs_create_file("mem_value", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_mem_value); + debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar, + &fops_mem_value); - debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy, - ar, &fops_chip_id); + debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar, + &fops_chip_id); - debugfs_create_file("htt_stats_mask", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_htt_stats_mask); + debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar, + &fops_htt_stats_mask); - debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, + debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar, &fops_htt_max_amsdu_ampdu); - debugfs_create_file("fw_dbglog", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_fw_dbglog); + debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar, + &fops_fw_dbglog); - debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, - ar, &fops_cal_data); + debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, + &fops_cal_data); - debugfs_create_file("ani_enable", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_ani_enable); + debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar, + &fops_ani_enable); - debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_nf_cal_period); + debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, + &fops_nf_cal_period); if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { - debugfs_create_file("dfs_simulate_radar", S_IWUSR, - ar->debug.debugfs_phy, ar, - &fops_simulate_radar); + debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy, + ar, &fops_simulate_radar); - debugfs_create_bool("dfs_block_radar_events", S_IWUSR, + debugfs_create_bool("dfs_block_radar_events", 0200, ar->debug.debugfs_phy, &ar->dfs_block_radar_events); - debugfs_create_file("dfs_stats", S_IRUSR, - ar->debug.debugfs_phy, ar, + debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar, &fops_dfs_stats); } - debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_pktlog_filter); + debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar, + &fops_pktlog_filter); - debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_quiet_period); + debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar, + &fops_quiet_period); - debugfs_create_file("tpc_stats", S_IRUSR, - ar->debug.debugfs_phy, ar, &fops_tpc_stats); + debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar, + &fops_tpc_stats); if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map)) - debugfs_create_file("btcoex", S_IRUGO | S_IWUSR, - ar->debug.debugfs_phy, ar, &fops_btcoex); + debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar, + &fops_btcoex); if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) - debugfs_create_file("peer_stats", S_IRUGO | S_IWUSR, - ar->debug.debugfs_phy, ar, + debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar, &fops_peer_stats); - debugfs_create_file("fw_checksums", S_IRUSR, - ar->debug.debugfs_phy, ar, &fops_fw_checksums); + debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, + &fops_fw_checksums); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 7353e7ea88f13..d59ac6b833400 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -372,11 +372,10 @@ static const struct file_operations fops_peer_debug_trigger = { void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { - debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, - &fops_aggr_mode); - debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); - debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); - debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); + debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); + debugfs_create_file("addba", 0200, dir, sta, &fops_addba); + debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); + debugfs_create_file("delba", 0200, dir, sta, &fops_delba); debugfs_create_file("peer_debug_trigger", 0600, dir, sta, &fops_peer_debug_trigger); } diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index c061d6958bd13..46471ed302752 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -536,15 +536,15 @@ int ath10k_spectral_create(struct ath10k *ar) 1140, 2500, &rfs_spec_scan_cb, NULL); debugfs_create_file("spectral_scan_ctl", - S_IRUSR | S_IWUSR, + 0600, ar->debug.debugfs_phy, ar, &fops_spec_scan_ctl); debugfs_create_file("spectral_count", - S_IRUSR | S_IWUSR, + 0600, ar->debug.debugfs_phy, ar, &fops_spectral_count); debugfs_create_file("spectral_bins", - S_IRUSR | S_IWUSR, + 0600, ar->debug.debugfs_phy, ar, &fops_spectral_bins); diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index f719d7d43cb0d..87948aff1bd5a 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -124,7 +124,7 @@ void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature) complete(&ar->thermal.wmi_sync); } -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp, +static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp, NULL, 0); static struct attribute *ath10k_hwmon_attrs[] = { From 37ff1b0df37af1f45d94674c83f65fc5ad4a3c73 Mon Sep 17 00:00:00 2001 From: Marcin Rokicki Date: Mon, 20 Feb 2017 15:38:50 +0100 Subject: [PATCH 010/201] ath10k: clean header files from bad block comments Fix output from checkpatch.pl like: Block comments use a trailing */ on a separate line Signed-off-by: Marcin Rokicki Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 3 ++- drivers/net/wireless/ath/ath10k/core.h | 9 ++++--- drivers/net/wireless/ath/ath10k/hif.h | 6 +++-- drivers/net/wireless/ath/ath10k/htt.h | 24 +++++++++++------ drivers/net/wireless/ath/ath10k/hw.h | 3 ++- drivers/net/wireless/ath/ath10k/rx_desc.h | 13 +++++---- drivers/net/wireless/ath/ath10k/targaddrs.h | 19 ++++++------- drivers/net/wireless/ath/ath10k/wmi-ops.h | 3 ++- drivers/net/wireless/ath/ath10k/wmi.h | 30 ++++++++++++++------- 9 files changed, 70 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index a65f26267fe34..cc45b63ade15e 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -176,7 +176,8 @@ union bmi_resp { } rompatch_uninstall; struct { /* 0 = nothing executed - * otherwise = NVRAM segment return value */ + * otherwise = NVRAM segment return value + */ __le32 result; } nvram_process; u8 payload[BMI_MAX_CMDBUF_SIZE]; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d4b9a0ec1bdc3..bf091514ecc6b 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -501,14 +501,16 @@ enum ath10k_state { * stopped in ath10k_core_restart() work holding conf_mutex. The state * RESTARTED means that the device is up and mac80211 has started hw * reconfiguration. Once mac80211 is done with the reconfiguration we - * set the state to STATE_ON in reconfig_complete(). */ + * set the state to STATE_ON in reconfig_complete(). + */ ATH10K_STATE_RESTARTING, ATH10K_STATE_RESTARTED, /* The device has crashed while restarting hw. This state is like ON * but commands are blocked in HTC and -ECOMM response is given. This * prevents completion timeouts and makes the driver more responsive to - * userspace commands. This is also prevents recursive recovery. */ + * userspace commands. This is also prevents recursive recovery. + */ ATH10K_STATE_WEDGED, /* factory tests */ @@ -920,7 +922,8 @@ struct ath10k { struct work_struct restart_work; /* cycle count is reported twice for each visited channel during scan. - * access protected by data_lock */ + * access protected by data_lock + */ u32 survey_last_rx_clear_count; u32 survey_last_cycle_count; struct survey_info survey[ATH10K_NUM_CHANS]; diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index b2566b06e1e1f..6679dd9cfd128 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -54,7 +54,8 @@ struct ath10k_hif_ops { int (*start)(struct ath10k *ar); /* Clean up what start() did. This does not revert to BMI phase. If - * desired so, call power_down() and power_up() */ + * desired so, call power_down() and power_up() + */ void (*stop)(struct ath10k *ar); int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, @@ -82,7 +83,8 @@ struct ath10k_hif_ops { int (*power_up)(struct ath10k *ar); /* Power down the device and free up resources. stop() must be called - * before this if start() was called earlier */ + * before this if start() was called earlier + */ void (*power_down)(struct ath10k *ar); int (*suspend)(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 90c2f72666b83..6305308422c44 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -51,7 +51,8 @@ enum htt_h2t_msg_type { /* host-to-target */ HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6, /* This command is used for sending management frames in HTT < 3.0. - * HTT >= 3.0 uses TX_FRM for everything. */ + * HTT >= 3.0 uses TX_FRM for everything. + */ HTT_H2T_MSG_TYPE_MGMT_TX = 7, HTT_H2T_MSG_TYPE_TX_FETCH_RESP = 11, @@ -910,7 +911,8 @@ struct htt_rx_test { /* payload consists of 2 lists: * a) num_ints * sizeof(__le32) - * b) num_chars * sizeof(u8) aligned to 4bytes */ + * b) num_chars * sizeof(u8) aligned to 4bytes + */ u8 payload[0]; } __packed; @@ -1307,7 +1309,8 @@ struct htt_frag_desc_bank_id { } __packed; /* real is 16 but it wouldn't fit in the max htt message size - * so we use a conservatively safe value for now */ + * so we use a conservatively safe value for now + */ #define HTT_FRAG_DESC_BANK_MAX 4 #define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03 @@ -1684,12 +1687,14 @@ struct ath10k_htt { DECLARE_KFIFO_PTR(txdone_fifo, struct htt_tx_done); /* set if host-fw communication goes haywire - * used to avoid further failures */ + * used to avoid further failures + */ bool rx_confused; atomic_t num_mpdus_ready; /* This is used to group tx/rx completions separately and process them - * in batches to reduce cache stalls */ + * in batches to reduce cache stalls + */ struct sk_buff_head rx_compl_q; struct sk_buff_head rx_in_ord_compl_q; struct sk_buff_head tx_fetch_ind_q; @@ -1725,11 +1730,13 @@ struct ath10k_htt { /* This structure layout is programmed via rx ring setup * so that FW knows how to transfer the rx descriptor to the host. - * Buffers like this are placed on the rx ring. */ + * Buffers like this are placed on the rx ring. + */ struct htt_rx_desc { union { /* This field is filled on the host using the msdu buffer - * from htt_rx_indication */ + * from htt_rx_indication + */ struct fw_rx_desc_base fw_desc; u32 pad; } __packed; @@ -1760,7 +1767,8 @@ struct htt_rx_desc { #define HTT_RX_MSDU_SIZE (HTT_RX_BUF_SIZE - (int)sizeof(struct htt_rx_desc)) /* Refill a bunch of RX buffers for each refill round so that FW/HW can handle - * aggregated traffic more nicely. */ + * aggregated traffic more nicely. + */ #define ATH10K_HTT_MAX_NUM_REFILL 100 /* diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index d370b573e0f9e..8aca62bca3487 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -296,7 +296,8 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap * - raw have FCS, nwifi doesn't * - ethernet frames have 802.11 header decapped and parts (base hdr, cipher - * param, llc/snap) are aligned to 4byte boundaries each */ + * param, llc/snap) are aligned to 4byte boundaries each + */ enum ath10k_hw_txrx_mode { ATH10K_HW_TXRX_RAW = 0, diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 034e7a54c5b27..c1022a1cf8555 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -439,19 +439,22 @@ struct rx_mpdu_end { * c) A-MSDU subframe header (14 bytes) if appliable * d) LLC/SNAP (RFC1042, 8 bytes) * - * In case of A-MSDU only first frame in sequence contains (a) and (b). */ + * In case of A-MSDU only first frame in sequence contains (a) and (b). + */ enum rx_msdu_decap_format { RX_MSDU_DECAP_RAW = 0, /* Note: QoS frames are reported as non-QoS. The rx_hdr_status in - * htt_rx_desc contains the original decapped 802.11 header. */ + * htt_rx_desc contains the original decapped 802.11 header. + */ RX_MSDU_DECAP_NATIVE_WIFI = 1, /* Payload contains an ethernet header (struct ethhdr). */ RX_MSDU_DECAP_ETHERNET2_DIX = 2, /* Payload contains two 48-bit addresses and 2-byte length (14 bytes - * total), followed by an RFC1042 header (8 bytes). */ + * total), followed by an RFC1042 header (8 bytes). + */ RX_MSDU_DECAP_8023_SNAP_LLC = 3 }; @@ -867,7 +870,7 @@ struct rx_ppdu_start { * * reserved_9 * Reserved: HW should fill with 0, FW should ignore. -*/ + */ #define RX_PPDU_END_FLAGS_PHY_ERR (1 << 0) #define RX_PPDU_END_FLAGS_RX_LOCATION (1 << 1) @@ -1207,7 +1210,7 @@ struct rx_ppdu_end { * Every time HW sets this bit in memory FW/SW must clear this * bit in memory. FW will initialize all the ppdu_done dword * to 0. -*/ + */ #define FW_RX_DESC_INFO0_DISCARD (1 << 0) #define FW_RX_DESC_INFO0_FORWARD (1 << 1) diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index a47cab44d9c85..cbac9e4252d6f 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -268,13 +268,13 @@ struct host_interest { #define HI_OPTION_FW_BRIDGE_SHIFT 0x04 /* -Fw Mode/SubMode Mask -|-----------------------------------------------------------------------------| -| SUB | SUB | SUB | SUB | | | | | -|MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0]| -| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) | -|-----------------------------------------------------------------------------| -*/ + * Fw Mode/SubMode Mask + *----------------------------------------------------------------------------- + * SUB | SUB | SUB | SUB | | | | + *MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0] + * (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) + *----------------------------------------------------------------------------- + */ #define HI_OPTION_FW_MODE_BITS 0x2 #define HI_OPTION_FW_MODE_MASK 0x3 #define HI_OPTION_FW_MODE_SHIFT 0xC @@ -428,8 +428,9 @@ Fw Mode/SubMode Mask #define HI_PWR_SAVE_LPL_ENABLED 0x1 /*b1-b3 reserved*/ /*b4-b5 : dev0 LPL type : 0 - none - 1- Reduce Pwr Search - 2- Reduce Pwr Listen*/ + * 1- Reduce Pwr Search + * 2- Reduce Pwr Listen + */ /*b6-b7 : dev1 LPL type and so on for Max 8 devices*/ #define HI_PWR_SAVE_LPL_DEV0_LSB 4 #define HI_PWR_SAVE_LPL_DEV_MASK 0x3 diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index c7956e181f80d..2fc3f24ff1caa 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -390,7 +390,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) return ret; /* FIXME There's no ACK event for Management Tx. This probably - * shouldn't be called here either. */ + * shouldn't be called here either. + */ info->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(ar->hw, msdu); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cf385feb5707e..1b4865a555954 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1038,7 +1038,8 @@ enum wmi_cmd_id { WMI_STA_UAPSD_AUTO_TRIG_CMDID, /* STA Keep alive parameter configuration, - Requires WMI_SERVICE_STA_KEEP_ALIVE */ + * Requires WMI_SERVICE_STA_KEEP_ALIVE + */ WMI_STA_KEEPALIVE_CMD, /* misc command group */ @@ -1774,7 +1775,8 @@ static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode) break; /* no default handler to allow compiler to check that the - * enum is fully handled */ + * enum is fully handled + */ }; return ""; @@ -2974,7 +2976,8 @@ struct wmi_start_scan_arg { /* When set, DFS channels will not be scanned */ #define WMI_SCAN_BYPASS_DFS_CHN 0x40 /* Different FW scan engine may choose to bail out on errors. - * Allow the driver to have influence over that. */ + * Allow the driver to have influence over that. + */ #define WMI_SCAN_CONTINUE_ON_ERROR 0x80 /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ @@ -4447,14 +4450,16 @@ enum wmi_vdev_subtype_10_4 { /* values for vdev_start_request flags */ /* * Indicates that AP VDEV uses hidden ssid. only valid for - * AP/GO */ + * AP/GO + */ #define WMI_VDEV_START_HIDDEN_SSID (1 << 0) /* * Indicates if robust management frame/management frame * protection is enabled. For GO/AP vdevs, it indicates that * it may support station/client associations with RMF enabled. * For STA/client vdevs, it indicates that sta will - * associate with AP with RMF enabled. */ + * associate with AP with RMF enabled. + */ #define WMI_VDEV_START_PMF_ENABLED (1 << 1) struct wmi_p2p_noa_descriptor { @@ -4814,7 +4819,8 @@ enum wmi_vdev_param { * An associated STA is considered unresponsive if there is no recent * TX/RX activity and downlink frames are buffered for it. Once a STA * exceeds the maximum unresponsive time, the AP will send a - * WMI_STA_KICKOUT event to the host so the STA can be deleted. */ + * WMI_STA_KICKOUT event to the host so the STA can be deleted. + */ WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, /* Enable NAWDS : MCAST INSPECT Enable, NAWDS Flag set */ @@ -4941,7 +4947,8 @@ enum wmi_10x_vdev_param { * An associated STA is considered unresponsive if there is no recent * TX/RX activity and downlink frames are buffered for it. Once a STA * exceeds the maximum unresponsive time, the AP will send a - * WMI_10X_STA_KICKOUT event to the host so the STA can be deleted. */ + * WMI_10X_STA_KICKOUT event to the host so the STA can be deleted. + */ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, /* Enable NAWDS : MCAST INSPECT Enable, NAWDS Flag set */ @@ -5605,12 +5612,14 @@ struct wmi_tim_info_arg { struct wmi_p2p_noa_info { /* Bit 0 - Flag to indicate an update in NOA schedule - Bits 7-1 - Reserved */ + * Bits 7-1 - Reserved + */ u8 changed; /* NOA index */ u8 index; /* Bit 0 - Opp PS state of the AP - Bits 1-7 - Ctwindow in TUs */ + * Bits 1-7 - Ctwindow in TUs + */ u8 ctwindow_oppps; /* Number of NOA descriptors */ u8 num_descriptors; @@ -6000,7 +6009,8 @@ struct wmi_main_peer_assoc_complete_cmd { struct wmi_common_peer_assoc_complete_cmd cmd; /* HT Operation Element of the peer. Five bytes packed in 2 - * INT32 array and filled from lsb to msb. */ + * INT32 array and filled from lsb to msb. + */ __le32 peer_ht_info[2]; } __packed; From 9415af7f306bfd5555552f059ea0a476c44c816a Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 17 Nov 2016 13:57:32 +0200 Subject: [PATCH 011/201] iwlwifi: mvm: support new binding API For a000 devices the binding API needs to include relevant lmac ID - support the new API. The new API should be used regardless if the device had CDB or not. If there is no actual CDB support the binding is bound to first lmac regardless of the band. There are some functionality changes in binding restrictions and quota allocations that will be handled in future patches. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-fw-file.h | 2 ++ .../net/wireless/intel/iwlwifi/mvm/binding.c | 17 ++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 16 ++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h | 14 +++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 14 ++++++++------ 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index d01701ee47770..9f639fdf0f6e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -344,6 +344,8 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, + IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c index 7cb68f6ed1b0d..2e0ed080457f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -82,6 +84,19 @@ static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt; int i, ret; u32 status; + int size; + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) { + size = sizeof(cmd); + if (phyctxt->channel->band == NL80211_BAND_2GHZ || + !iwl_mvm_is_cdb_supported(mvm)) + cmd.lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX); + else + cmd.lmac_id = cpu_to_le32(IWL_LMAC_5G_INDEX); + } else { + size = IWL_BINDING_CMD_SIZE_V1; + } memset(&cmd, 0, sizeof(cmd)); @@ -99,7 +114,7 @@ static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, status = 0; ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, - sizeof(cmd), &cmd, &status); + size, &cmd, &status); if (ret) { IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n", action, ret); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index c7eb1983c4f9a..b7465857b4b65 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -665,6 +665,19 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_binding_cmd binding_cmd = {}; struct iwl_time_quota_cmd quota_cmd = {}; u32 status; + int size; + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) { + size = sizeof(binding_cmd); + if (mvmvif->phy_ctxt->channel->band == NL80211_BAND_2GHZ || + !iwl_mvm_is_cdb_supported(mvm)) + binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX); + else + binding_cmd.lmac_id = cpu_to_le32(IWL_LMAC_5G_INDEX); + } else { + size = IWL_BINDING_CMD_SIZE_V1; + } /* add back the PHY */ if (WARN_ON(!mvmvif->phy_ctxt)) @@ -711,8 +724,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, status = 0; ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD, - sizeof(binding_cmd), &binding_cmd, - &status); + size, &binding_cmd, &status); if (ret) { IWL_ERR(mvm, "Failed to add binding: %d\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index cf2b836f38881..248373a0990a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -673,10 +673,8 @@ struct iwl_error_resp { /* Common PHY, MAC and Bindings definitions */ - #define MAX_MACS_IN_BINDING (3) #define MAX_BINDINGS (4) -#define AUX_BINDING_INDEX (3) /* Used to extract ID and color from the context dword */ #define FW_CTXT_ID_POS (0) @@ -960,6 +958,7 @@ struct iwl_time_event_notif { * @action: action to perform, one of FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding * @phy: PHY id and color which belongs to the binding + * @lmac_id: the lmac id the binding belongs to */ struct iwl_binding_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ @@ -968,7 +967,13 @@ struct iwl_binding_cmd { /* BINDING_DATA_API_S_VER_1 */ __le32 macs[MAX_MACS_IN_BINDING]; __le32 phy; -} __packed; /* BINDING_CMD_API_S_VER_1 */ + /* BINDING_CMD_API_S_VER_1 */ + __le32 lmac_id; +} __packed; /* BINDING_CMD_API_S_VER_2 */ + +#define IWL_BINDING_CMD_SIZE_V1 offsetof(struct iwl_binding_cmd, lmac_id) +#define IWL_LMAC_24G_INDEX 0 +#define IWL_LMAC_5G_INDEX 1 /* The maximal number of fragments in the FW's schedule session */ #define IWL_MVM_MAX_QUOTA 128 @@ -990,6 +995,9 @@ struct iwl_time_quota_data { * struct iwl_time_quota_cmd - configuration of time quota between bindings * ( TIME_QUOTA_CMD = 0x2c ) * @quotas: allocations per binding + * Note: on non-CDB the fourth one is the auxilary mac and is + * essentially zero. + * On CDB the fourth one is a regular binding. */ struct iwl_time_quota_cmd { struct iwl_time_quota_data quotas[MAX_BINDINGS]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 73a216524af29..88bc459b1f9a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1222,13 +1222,15 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) { /* * TODO: - * The issue of how to determine CDB support is still not well defined. - * It may be that it will be for all next HW devices and it may be per - * FW compilation and it may also differ between different devices. - * For now take a ride on the new TX API and get back to it when - * it is well defined. + * The issue of how to determine CDB APIs and usage is still not fully + * defined. + * There is a compilation for CDB and non-CDB FW, but there may + * be also runtime check. + * For now there is a TLV for checking compilation mode, but a + * runtime check will also have to be here - once defined. */ - return iwl_mvm_has_new_tx_api(mvm); + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) From 6ffff630c0699ded5c3e79879cc9c4e733a46829 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 28 Dec 2016 10:46:20 +0200 Subject: [PATCH 012/201] iwlwifi: be more verbose about needed firmware If the supported firmware versions are not found, we currently only print "no suitable firmware found". This is not very informative for the user trying to find the correct version to use. Improve this by printing the exact firmware name(s) the driver supports and pointing to the git repository where they can be found. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 23 ++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index be466a074c1df..21c523a9cc7e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -211,24 +211,39 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, static int iwl_request_firmware(struct iwl_drv *drv, bool first) { - const char *name_pre = drv->trans->cfg->fw_name_pre; + const struct iwl_cfg *cfg = drv->trans->cfg; char tag[8]; if (first) { - drv->fw_index = drv->trans->cfg->ucode_api_max; + drv->fw_index = cfg->ucode_api_max; sprintf(tag, "%d", drv->fw_index); } else { drv->fw_index--; sprintf(tag, "%d", drv->fw_index); } - if (drv->fw_index < drv->trans->cfg->ucode_api_min) { + if (drv->fw_index < cfg->ucode_api_min) { IWL_ERR(drv, "no suitable firmware found!\n"); + + if (cfg->ucode_api_min == cfg->ucode_api_max) { + IWL_ERR(drv, "%s%d is required\n", cfg->fw_name_pre, + cfg->ucode_api_max); + } else { + IWL_ERR(drv, "minimum version required: %s%d\n", + cfg->fw_name_pre, + cfg->ucode_api_min); + IWL_ERR(drv, "maximum version supported: %s%d\n", + cfg->fw_name_pre, + cfg->ucode_api_max); + } + + IWL_ERR(drv, + "check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git\n"); return -ENOENT; } snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", - name_pre, tag); + cfg->fw_name_pre, tag); IWL_DEBUG_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); From ddef2f98eee55deb7923917d388e7715310c3aa9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 19 Dec 2016 08:41:16 +0200 Subject: [PATCH 013/201] iwlwifi: mvm: add DQA_ENABLE_CMD to the command list This will allow to print the name of the commands in the logs when we sent it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4cd72d4cdc47c..f4f957fe71d7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -452,6 +452,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { * Access is done through binary search */ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { + HCMD_NAME(DQA_ENABLE_CMD), HCMD_NAME(UPDATE_MU_GROUPS_CMD), HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), HCMD_NAME(STA_PM_NOTIF), From 63f231fea02afbd364bbe77717bdee5a22daedd1 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 27 Dec 2016 10:18:18 +0200 Subject: [PATCH 014/201] iwlwifi: remove support for deprecated RF One of the RF modules we support has been deprecated and never released publicly. Remove support for this module. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 19 ------------------- .../net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 1 - drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 17 +++++------------ 4 files changed, 5 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index a5f0c0bf85ec8..ca119bd8a32b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -74,13 +74,10 @@ #define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" #define IWL9260_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" -#define IWL9000LC_FW_PRE "iwlwifi-9000-pu-a0-lc-a0-" #define IWL9000_MODULE_FIRMWARE(api) \ IWL9000_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260_MODULE_FIRMWARE(api) \ IWL9260_FW_PRE "-" __stringify(api) ".ucode" -#define IWL9000LC_MODULE_FIRMWARE(api) \ - IWL9000LC_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_9000 10 @@ -198,21 +195,5 @@ const struct iwl_cfg iwl9560_2ac_cfg = { .integrated = true, }; -/* - * TODO the struct below is for internal testing only this should be - * removed by EO 2016~ - */ -const struct iwl_cfg iwl9000lc_2ac_cfg = { - .name = "Intel(R) Dual Band Wireless AC 9000", - .fw_name_pre = IWL9000LC_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, -}; - MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9260_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9000LC_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 94f8a51b633eb..96a2ec32f7073 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -449,7 +449,6 @@ extern const struct iwl_cfg iwl4165_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; extern const struct iwl_cfg iwl8265_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; -extern const struct iwl_cfg iwl9000lc_2ac_cfg; extern const struct iwl_cfg iwl9160_2ac_cfg; extern const struct iwl_cfg iwl9260_2ac_cfg; extern const struct iwl_cfg iwl9270_2ac_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 4ee3b621ec27a..fa120fb553737 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -348,7 +348,6 @@ enum { /* RF_ID value */ #define CSR_HW_RF_ID_TYPE_JF (0x00105000) -#define CSR_HW_RF_ID_TYPE_LC (0x00101000) #define CSR_HW_RF_ID_TYPE_HR (0x00109000) /* EEPROM REG */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index ba8a81cb0e2b7..d38fcc1a47683 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -667,18 +667,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_trans->cfg = cfg_7265d; } - if (iwl_trans->cfg->rf_id) { - if (cfg == &iwl9460_2ac_cfg && - iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_LC) { - cfg = &iwl9000lc_2ac_cfg; - iwl_trans->cfg = cfg; - } - - if (cfg == &iwla000_2ac_cfg_hr && - iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) { - cfg = &iwla000_2ac_cfg_jf; - iwl_trans->cfg = cfg; - } + if (iwl_trans->cfg->rf_id && + (cfg == &iwla000_2ac_cfg_hr && + iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF)) { + cfg = &iwla000_2ac_cfg_jf; + iwl_trans->cfg = cfg; } #endif From 2876e8c9e8a5bf075c7eddad4d309c1bdd178177 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 19 Dec 2016 12:00:32 +0200 Subject: [PATCH 015/201] iwlwifi: mvm: bump max API to 30 Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-7000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index a72e58623d3ab..aeefd42d23ad4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -73,8 +73,8 @@ /* Highest firmware API version supported */ #define IWL7260_UCODE_API_MAX 17 #define IWL7265_UCODE_API_MAX 17 -#define IWL7265D_UCODE_API_MAX 28 -#define IWL3168_UCODE_API_MAX 28 +#define IWL7265D_UCODE_API_MAX 30 +#define IWL3168_UCODE_API_MAX 30 /* Lowest firmware API version supported */ #define IWL7260_UCODE_API_MIN 17 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index b7953bf55f6fe..b9718c0cf1748 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 28 -#define IWL8265_UCODE_API_MAX 28 +#define IWL8000_UCODE_API_MAX 30 +#define IWL8265_UCODE_API_MAX 30 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 17 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index ca119bd8a32b9..da58ece2286a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 28 +#define IWL9000_UCODE_API_MAX 30 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 17 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 15dd7f6137c8f..20739e92aef6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 28 +#define IWL_A000_UCODE_API_MAX 30 /* Lowest firmware API version supported */ #define IWL_A000_UCODE_API_MIN 24 From 951cb319872df74a7ec2f3a13cebc0f2422cbdba Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 29 Dec 2016 10:11:40 +0200 Subject: [PATCH 016/201] iwlwifi: mvm: adjust new API of compressed BA Final API has a reserved field - adjust accordingly. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index b38cc073adcc7..85744fa3bd4d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -635,6 +635,10 @@ enum iwl_mvm_ba_resp_flags { * @tx_rate: the rate the aggregation was sent at * @tfd_cnt: number of TFD-Q elements * @ra_tid_cnt: number of RATID-Q elements + * @ba_tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd + * for details. + * @ra_tid: array of RA-TID queue status updates. For debug purposes only. See + * &iwl_mvm_compressed_ba_ratid for more details. */ struct iwl_mvm_compressed_ba_notif { __le32 flags; @@ -646,6 +650,7 @@ struct iwl_mvm_compressed_ba_notif { __le16 query_frame_cnt; __le16 txed; __le16 done; + __le16 reserved; __le32 wireless_time; __le32 tx_rate; __le16 tfd_cnt; From 5cddd05c9cbe420436799716d009bc0372ef8268 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Dec 2016 13:48:04 +0100 Subject: [PATCH 017/201] iwlwifi: mvm: fix RX SKB header size and align it properly When receiving a frame, we currently pull in sizeof(*hdr) plus some extra (crypto/snap), which is too much, most headers aren't actually sizeof(*hdr) since that takes into account the 4-address format but doesn't take into account QoS. As a result, a typical frame will have 4 bytes of the payload in the SKB header already. Fix this by calculating the correct header length, and now that we have that, align the end of the SKB header to a multiple of 4 so that the IP header will be aligned properly when pulled in. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 20473df79c945..c1bf67f04cf60 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -104,7 +104,20 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { - unsigned int hdrlen, fraglen; + unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); + unsigned int fraglen; + + /* + * The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len, + * but those are all multiples of 4 long) all goes away, but we + * want the *end* of it, which is going to be the start of the IP + * header, to be aligned when it gets pulled in. + * The beginning of the skb->data is aligned on at least a 4-byte + * boundary after allocation. Everything here is aligned at least + * on a 2-byte boundary so we can just take hdrlen & 3 and pad by + * the result. + */ + skb_reserve(skb, hdrlen & 3); /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and @@ -118,8 +131,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ - hdrlen = (len <= skb_tailroom(skb)) ? len : - sizeof(*hdr) + crypt_len + 8; + hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; memcpy(skb_put(skb, hdrlen), hdr, hdrlen); fraglen = len - hdrlen; From afb844318de2a87694380ee3824ee102f2699bd9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 3 Jan 2017 10:04:44 +0200 Subject: [PATCH 018/201] iwlwifi: pcie: print less data upon firmware crash We don't need to print so much data in the kernel log. Limit the data to be printed to the queue that actually got stuck in case of a TFD queue hang, and stop dumping all the CSR and FH registers. Over the course of time, the CSR and FH values haven't proven themselves to be really useful for debugging, and they are now in the firmware dump anyway. This comes as a preparation to the addition of more data required to be printed by the firwmare team. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 3 - .../net/wireless/intel/iwlwifi/pcie/trans.c | 64 +++++++------------ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 - 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index de94dfdf2ec99..17806d82f3a3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1393,9 +1393,6 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) return; } - iwl_pcie_dump_csr(trans); - iwl_dump_fh(trans, NULL); - local_bh_disable(); /* The STATUS_FW_ERROR bit is set in this function. This must happen * before we wake up the command caller, to ensure a proper cleanup. */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 7f05fc56587ad..fbb0afa9de142 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -2075,48 +2075,32 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 scd_sram_addr; - u8 buf[16]; - int cnt; + u32 txq_id = txq->id; + u32 status; + bool active; + u8 fifo; - IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", - txq->read_ptr, txq->write_ptr); - - if (trans->cfg->use_tfh) + if (trans->cfg->use_tfh) { + IWL_ERR(trans, "Queue %d is stuck %d %d\n", txq_id, + txq->read_ptr, txq->write_ptr); /* TODO: access new SCD registers and dump them */ return; - - scd_sram_addr = trans_pcie->scd_base_addr + - SCD_TX_STTS_QUEUE_OFFSET(txq->id); - iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf)); - - iwl_print_hex_error(trans, buf, sizeof(buf)); - - for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++) - IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt, - iwl_read_direct32(trans, FH_TX_TRB_REG(cnt))); - - for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt)); - u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; - bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); - u32 tbl_dw = - iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(cnt)); - - if (cnt & 0x1) - tbl_dw = (tbl_dw & 0xFFFF0000) >> 16; - else - tbl_dw = tbl_dw & 0x0000FFFF; - - IWL_ERR(trans, - "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n", - cnt, active ? "" : "in", fifo, tbl_dw, - iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) & - (TFD_QUEUE_SIZE_MAX - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); } + + status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id)); + fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; + active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); + + IWL_ERR(trans, + "Queue %d is %sactive on fifo %d and stuck for %u ms. SW [%d, %d] HW [%d, %d] FH TRB=0x0%x\n", + txq_id, active ? "" : "in", fifo, + jiffies_to_msecs(txq->wd_timeout), + txq->read_ptr, txq->write_ptr, + iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & + (TFD_QUEUE_SIZE_MAX - 1), + iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)) & + (TFD_QUEUE_SIZE_MAX - 1), + iwl_read_direct32(trans, FH_TX_TRB_REG(fifo))); } static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 911cf98681074..03df578bed008 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -164,9 +164,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) } spin_unlock(&txq->lock); - IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->id, - jiffies_to_msecs(txq->wd_timeout)); - iwl_trans_pcie_log_scd_error(trans, txq); iwl_force_nmi(trans); From 1c17627bf5c460f94451ac5acab3ee96d3b7e1cd Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 22 Dec 2016 13:03:40 +0200 Subject: [PATCH 019/201] iwlwifi: mvm: cleanup pending frames in DQA mode When a station is asleep, the fw will set it as "asleep". All queues that are used only by one station will be stopped by the fw. In pre-DQA mode this was relevant for aggregation queues. However, in DQA mode a queue is owned by one station only, so all queues will be stopped. As a result, we don't expect to get filtered frames back to mac80211 and don't have to maintain the entire pending_frames state logic, the same way as we do in aggregations. The correct behavior is to align DQA behavior with the aggregation queue behaviour pre-DQA: - Don't count pending frames. - Let mac80211 know we have frames in these queues so that it can properly handle trigger frames. When a trigger frame is received, mac80211 tells the driver to send frames from the queues using release_buffered_frames. The driver will tell the fw to let frames out even if the station is asleep. This is done by iwl_mvm_sta_modify_sleep_tx_count. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 8 +++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 11 ++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 41 ++++++++----------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d37b1695c64ea..265d9eb8f0b02 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2319,7 +2319,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* Called when we need to transmit (a) frame(s) from agg queue */ + /* Called when we need to transmit (a) frame(s) from agg or dqa queue */ iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, tids, more_data, true); @@ -2338,10 +2338,14 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - if (tid_data->state != IWL_AGG_ON && + if (!iwl_mvm_is_dqa_supported(mvm) && + tid_data->state != IWL_AGG_ON && tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) continue; + if (tid_data->txq_id == IEEE80211_INVAL_HW_QUEUE) + continue; + __set_bit(tid_data->txq_id, &txqs); if (iwl_mvm_tid_queued(tid_data) == 0) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bd1dcc863d8f3..b51a2853cc804 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3135,7 +3135,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum ieee80211_frame_release_type reason, u16 cnt, u16 tids, bool more_data, - bool agg) + bool single_sta_queue) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = { @@ -3155,14 +3155,14 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]); - /* If we're releasing frames from aggregation queues then check if the - * all queues combined that we're releasing frames from have + /* If we're releasing frames from aggregation or dqa queues then check + * if all the queues that we're releasing frames from, combined, have: * - more frames than the service period, in which case more_data * needs to be set * - fewer than 'cnt' frames, in which case we need to adjust the * firmware command (but do that unconditionally) */ - if (agg) { + if (single_sta_queue) { int remaining = cnt; int sleep_tx_count; @@ -3172,7 +3172,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, u16 n_queued; tid_data = &mvmsta->tid_data[tid]; - if (WARN(tid_data->state != IWL_AGG_ON && + if (WARN(!iwl_mvm_is_dqa_supported(mvm) && + tid_data->state != IWL_AGG_ON && tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, "TID %d state is %d\n", tid, tid_data->state)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 4be34f902278c..1927ce6077984 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -547,7 +547,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum ieee80211_frame_release_type reason, u16 cnt, u16 tids, bool more_data, - bool agg); + bool single_sta_queue); int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool drain); void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index dd2b4a3008199..3f37075f4cde3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -628,8 +629,10 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) * values. * Note that we don't need to make sure it isn't agg'd, since we're * TXing non-sta + * For DQA mode - we shouldn't increase it though */ - atomic_inc(&mvm->pending_frames[sta_id]); + if (!iwl_mvm_is_dqa_supported(mvm)) + atomic_inc(&mvm->pending_frames[sta_id]); return 0; } @@ -1005,11 +1008,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, spin_unlock(&mvmsta->lock); - /* Increase pending frames count if this isn't AMPDU */ - if ((iwl_mvm_is_dqa_supported(mvm) && - mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_ON && - mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_STARTING) || - (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu)) + /* Increase pending frames count if this isn't AMPDU or DQA queue */ + if (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu) atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); return 0; @@ -1079,12 +1079,13 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, lockdep_assert_held(&mvmsta->lock); if ((tid_data->state == IWL_AGG_ON || - tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && + tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA || + iwl_mvm_is_dqa_supported(mvm)) && iwl_mvm_tid_queued(tid_data) == 0) { /* - * Now that this aggregation queue is empty tell mac80211 so it - * knows we no longer have frames buffered for the station on - * this TID (for the TIM bitmap calculation.) + * Now that this aggregation or DQA queue is empty tell + * mac80211 so it knows we no longer have frames buffered for + * the station on this TID (for the TIM bitmap calculation.) */ ieee80211_sta_set_buffered(sta, tid, false); } @@ -1257,7 +1258,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, u8 skb_freed = 0; u16 next_reclaimed, seq_ctl; bool is_ndp = false; - bool txq_agg = false; /* Is this TXQ aggregated */ __skb_queue_head_init(&skbs); @@ -1283,6 +1283,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, info->flags |= IEEE80211_TX_STAT_ACK; break; case TX_STATUS_FAIL_DEST_PS: + /* In DQA, the FW should have stopped the queue and not + * return this status + */ + WARN_ON(iwl_mvm_is_dqa_supported(mvm)); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; break; default: @@ -1387,15 +1391,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, bool send_eosp_ndp = false; spin_lock_bh(&mvmsta->lock); - if (iwl_mvm_is_dqa_supported(mvm)) { - enum iwl_mvm_agg_state state; - - state = mvmsta->tid_data[tid].state; - txq_agg = (state == IWL_AGG_ON || - state == IWL_EMPTYING_HW_QUEUE_DELBA); - } else { - txq_agg = txq_id >= mvm->first_agg_queue; - } if (!is_ndp) { tid_data->next_reclaimed = next_reclaimed; @@ -1452,11 +1447,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, * If the txq is not an AMPDU queue, there is no chance we freed * several skbs. Check that out... */ - if (txq_agg) + if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) goto out; /* We can't free more than one frame at once on a shared queue */ - WARN_ON(!iwl_mvm_is_dqa_supported(mvm) && (skb_freed > 1)); + WARN_ON(skb_freed > 1); /* If we have still frames for this STA nothing to do here */ if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) From bd31dd9d147aad423a9ac371b86685f87b4e1420 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 9 Jan 2017 11:28:47 +0100 Subject: [PATCH 020/201] iwlwifi: use upper_32_bits/lower_32_bits where appropriate That's a bit nicer than open-coding it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 33ef5372d1951..361fc25e8618c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -647,7 +647,7 @@ struct iwl_rb_status { static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) { - return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; + return (sizeof(addr) > sizeof(u32) ? upper_32_bits(addr) : 0) & 0xF; } /** * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index a9f69fdd170b0..0f893ae6e715b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -54,8 +54,8 @@ IWL_EXPORT_SYMBOL(iwl_write32); void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val) { trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val); - iwl_trans_write32(trans, ofs, val & 0xffffffff); - iwl_trans_write32(trans, ofs + 4, val >> 32); + iwl_trans_write32(trans, ofs, lower_32_bits(val)); + iwl_trans_write32(trans, ofs + 4, upper_32_bits(val)); } IWL_EXPORT_SYMBOL(iwl_write64); From 5da083d1922c23b75e921c85b687c8e112e8280e Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 8 Jan 2017 16:52:59 +0200 Subject: [PATCH 021/201] iwlwifi: add support for 9000 HW B-step NICs Once we remove support for A-step, we'll be able to clean the code back again. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 25 ++++++++++++------- .../net/wireless/intel/iwlwifi/iwl-config.h | 7 ++++-- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 19 +++++++++----- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index da58ece2286a1..d265b279b2caf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2015-2016 Intel Deutschland GmbH + * Copyright(c) 2015-2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,7 +18,7 @@ * * BSD LICENSE * - * Copyright(c) 2015-2016 Intel Deutschland GmbH + * Copyright(c) 2015-2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,11 +73,14 @@ #define IWL9000_SMEM_LEN 0x68000 #define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" -#define IWL9260_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" +#define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" +#define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" #define IWL9000_MODULE_FIRMWARE(api) \ IWL9000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL9260_MODULE_FIRMWARE(api) \ - IWL9260_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9260A_MODULE_FIRMWARE(api) \ + IWL9260A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL9260B_MODULE_FIRMWARE(api) \ + IWL9260B_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_9000 10 @@ -145,7 +148,8 @@ static const struct iwl_tt_params iwl9000_tt_params = { const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", - .fw_name_pre = IWL9260_FW_PRE, + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -155,7 +159,8 @@ const struct iwl_cfg iwl9160_2ac_cfg = { const struct iwl_cfg iwl9260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9260", - .fw_name_pre = IWL9260_FW_PRE, + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -165,7 +170,8 @@ const struct iwl_cfg iwl9260_2ac_cfg = { const struct iwl_cfg iwl9270_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9270", - .fw_name_pre = IWL9260_FW_PRE, + .fw_name_pre = IWL9260A_FW_PRE, + .fw_name_pre_next_step = IWL9260B_FW_PRE, IWL_DEVICE_9000, .ht_params = &iwl9000_ht_params, .nvm_ver = IWL9000_NVM_VERSION, @@ -196,4 +202,5 @@ const struct iwl_cfg iwl9560_2ac_cfg = { }; MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9260_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 96a2ec32f7073..852963487bd91 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2016 Intel Deutschland GmbH + * Copyright (C) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2016 Intel Deutschland GmbH + * Copyright (C) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -283,6 +283,8 @@ struct iwl_pwr_tx_backoff { * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The * filename is constructed as fw_name_pre.ucode. + * @fw_name_pre_next_step: same as @fw_name_pre, only for next step + * (if supported) * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @max_inst_size: The maximal length of the fw inst section @@ -330,6 +332,7 @@ struct iwl_cfg { /* params specific to an individual device within a device family */ const char *name; const char *fw_name_pre; + const char *fw_name_pre_next_step; /* params not likely to change within a device family */ const struct iwl_base_params *base_params; /* params likely to change within a device family */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 21c523a9cc7e7..212fb8d5c0642 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -213,6 +213,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) { const struct iwl_cfg *cfg = drv->trans->cfg; char tag[8]; + const char *fw_pre_name; + + if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP) + fw_pre_name = cfg->fw_name_pre_next_step; + else + fw_pre_name = cfg->fw_name_pre; if (first) { drv->fw_index = cfg->ucode_api_max; @@ -226,14 +233,14 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (cfg->ucode_api_min == cfg->ucode_api_max) { - IWL_ERR(drv, "%s%d is required\n", cfg->fw_name_pre, + IWL_ERR(drv, "%s%d is required\n", fw_pre_name, cfg->ucode_api_max); } else { IWL_ERR(drv, "minimum version required: %s%d\n", - cfg->fw_name_pre, + fw_pre_name, cfg->ucode_api_min); IWL_ERR(drv, "maximum version supported: %s%d\n", - cfg->fw_name_pre, + fw_pre_name, cfg->ucode_api_max); } @@ -243,7 +250,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) } snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", - cfg->fw_name_pre, tag); + fw_pre_name, tag); IWL_DEBUG_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); From 26d6c16bed536be526cbfcf67ceefb410d62f252 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 3 Jan 2017 12:00:19 +0200 Subject: [PATCH 022/201] iwlwifi: mvm: add multicast station Currently multicast queue is associated with the broadcast station. This raises quite a few issues: The multicast queue has a special treatment: - It is sent in the MAC context command - It is excluded from tfd_queue_mask In DQA mode we end up enabling two queues - the probe response queue and the multicast queue - with the same station (broadcast) and TID while in DQA mode it should be unique RA-TID. Firmware will enforce it for a000 devices, so this allocation will fail. In addition, in a000 devices the FW will set the FIFO and not the driver. So there is a need for FW to know when we enable the queue that it is multicast queue so it will be bound to the multicast FIFO. There is no such way in current design. In order to simplify driver and firmware handling of this queue create a multicast station. This solves the unique RA-TID issue in the short term and serves as preparation for the long term. In the long term we will also add a flag marking this station for the FW as the multicast station. Once we will do that the FW will know this is the multicast queue immediately when it is added and bind it to the correct FIFO. It will also enable removing the special treatment of the queue in the MAC context command. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 1 + .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 26 +++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 112 ++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 3 + 5 files changed, 106 insertions(+), 37 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 99132ea16ede0..e7c8567cafffd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -472,6 +472,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, } mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; + mvmvif->mcast_sta.sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 265d9eb8f0b02..72a056a80516e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -6,8 +6,8 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,7 +33,8 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1351,6 +1352,17 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_release; } + if (iwl_mvm_is_dqa_supported(mvm)) { + /* + * Only queue for this station is the mcast queue, + * which shouldn't be in TFD mask anyway + */ + ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->mcast_sta, + 0, vif->type); + if (ret) + goto out_release; + } + iwl_mvm_vif_dbgfs_register(mvm, vif); goto out_unlock; } @@ -1516,6 +1528,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, mvm->noa_duration = 0; } #endif + iwl_mvm_dealloc_int_sta(mvm, &mvmvif->mcast_sta); iwl_mvm_dealloc_bcast_sta(mvm, vif); goto out_release; } @@ -2104,6 +2117,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_unbind; + ret = iwl_mvm_add_mcast_sta(mvm, vif); + if (ret) + goto out_rm_bcast; + /* must be set before quota calculations */ mvmvif->ap_ibss_active = true; @@ -2131,6 +2148,8 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, out_quota_failed: iwl_mvm_power_update_mac(mvm); mvmvif->ap_ibss_active = false; + iwl_mvm_rm_mcast_sta(mvm, vif); +out_rm_bcast: iwl_mvm_send_rm_bcast_sta(mvm, vif); out_unbind: iwl_mvm_binding_remove_vif(mvm, vif); @@ -2177,6 +2196,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); iwl_mvm_update_quotas(mvm, false, NULL); + iwl_mvm_rm_mcast_sta(mvm, vif); iwl_mvm_send_rm_bcast_sta(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 88bc459b1f9a7..70b9946382735 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -407,6 +407,7 @@ struct iwl_mvm_vif { struct iwl_mvm_time_event_data hs_time_event_data; struct iwl_mvm_int_sta bcast_sta; + struct iwl_mvm_int_sta mcast_sta; /* * Assigned while mac80211 has the interface in a channel context, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b51a2853cc804..41fd3ba574c05 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1652,8 +1652,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, return 0; } -static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta) +void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); @@ -1826,33 +1825,8 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, mvmvif->id, mvmvif->color); - if (ret) - return ret; - - /* - * In AP vif type, we also need to enable the cab_queue. However, we - * have to enable it after the ADD_STA command is sent, otherwise the - * FW will throw an assert once we send the ADD_STA command (it'll - * detect a mismatch in the tfd_queue_msk, as we can't add the - * enabled-cab_queue to the mask) - */ - if (iwl_mvm_is_dqa_supported(mvm) && - vif->type == NL80211_IFTYPE_AP) { - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = IWL_MVM_TX_FIFO_MCAST, - .sta_id = mvmvif->bcast_sta.sta_id, - .tid = IWL_MAX_TID_COUNT, - .aggregate = false, - .frame_limit = IWL_FRAME_LIMIT, - }; - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, vif, false, false); - - iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, - 0, &cfg, wdg_timeout); - } - return 0; + return ret; } static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, @@ -1862,10 +1836,6 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (vif->type == NL80211_IFTYPE_AP) - iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); - if (mvmvif->bcast_sta.tfd_queue_msk & BIT(IWL_MVM_DQA_AP_PROBE_RESP_QUEUE)) { iwl_mvm_disable_txq(mvm, @@ -1979,6 +1949,80 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; } +/* + * Allocate a new station entry for the multicast station to the given vif, + * and send it to the FW. + * Note that each AP/GO mac should have its own multicast station. + * + * @mvm: the mvm component + * @vif: the interface to which the multicast station is added + */ +int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_int_sta *msta = &mvmvif->mcast_sta; + static const u8 _maddr[] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; + const u8 *maddr = _maddr; + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = IWL_MVM_TX_FIFO_MCAST, + .sta_id = msta->sta_id, + .tid = IWL_MAX_TID_COUNT, + .aggregate = false, + .frame_limit = IWL_FRAME_LIMIT, + }; + unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif, false, false); + int ret; + + lockdep_assert_held(&mvm->mutex); + + if (!iwl_mvm_is_dqa_supported(mvm)) + return 0; + + if (WARN_ON(vif->type != NL80211_IFTYPE_AP)) + return -ENOTSUPP; + + ret = iwl_mvm_add_int_sta_common(mvm, msta, maddr, + mvmvif->id, mvmvif->color); + if (ret) { + iwl_mvm_dealloc_int_sta(mvm, msta); + return ret; + } + + /* + * Enable cab queue after the ADD_STA command is sent. + * This is needed for a000 firmware which won't accept SCD_QUEUE_CFG + * command with unknown station id. + */ + iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, &cfg, + timeout); + + return 0; +} + +/* + * Send the FW a request to remove the station from it's internal data + * structures, and in addition remove it from the local data structure. + */ +int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; + + lockdep_assert_held(&mvm->mutex); + + if (!iwl_mvm_is_dqa_supported(mvm)) + return 0; + + iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, + IWL_MAX_TID_COUNT, 0); + + ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); + if (ret) + IWL_WARN(mvm, "Failed sending remove station\n"); + + return ret; +} + #define IWL_MAX_RX_BA_SESSIONS 16 static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm, u8 baid) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 1927ce6077984..a143a8757e278 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -532,10 +532,13 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta, u32 qmask, enum nl80211_iftype iftype); void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta); int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm); From 45c458b4c0cad854bb1ae150e637dfe9c5108337 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 9 Nov 2016 15:43:26 +0200 Subject: [PATCH 023/201] iwlwifi: mvm: support new ADD_MODIFY_STA_KEY command The command was changed to support PN offload and TKIP offload. The FW will do TKIP calculations in D0 only for a000 devices, but API is aligned anyway. However, for all devices we can stop sending the wowlan tkip command. Firmware will fetch the keys from the station key command. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-fw-file.h | 3 + drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 +- .../wireless/intel/iwlwifi/mvm/fw-api-sta.h | 34 +++++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 96 +++++++++++++------ 4 files changed, 102 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 9f639fdf0f6e5..287e83eb30d98 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -241,6 +241,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * iteration complete notification, and the timestamp reported for RX * received during scan, are reported in TSF of the mac specified in the * scan request. + * @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of + * ADD_MODIFY_STA_KEY_API_S_VER_2. * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -250,6 +252,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_LQ_SS_PARAMS = (__force iwl_ucode_tlv_api_t)18, IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index b7465857b4b65..d65acfa3b89b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -998,7 +998,9 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, goto out; } - if (key_data.use_tkip) { + if (key_data.use_tkip && + !fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS)) { ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TKIP_PARAM, cmd_flags, sizeof(tkip_cmd), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 3b5150e9975d6..cd5fdf83d0403 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -389,27 +389,49 @@ struct iwl_mvm_add_sta_cmd { } __packed; /* ADD_STA_CMD_API_S_VER_8 */ /** - * struct iwl_mvm_add_sta_key_cmd - add/modify sta key + * struct iwl_mvm_add_sta_key_common - add/modify sta key common part * ( REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage * @key_flags: type %iwl_sta_key_flag * @key: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key - * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection - * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ -struct iwl_mvm_add_sta_key_cmd { +struct iwl_mvm_add_sta_key_common { u8 sta_id; u8 key_offset; __le16 key_flags; u8 key[32]; u8 rx_secur_seq_cnt[16]; +} __packed; + +/** + * struct iwl_mvm_add_sta_key_cmd_v1 - add/modify sta key + * @common: see &struct iwl_mvm_add_sta_key_common + * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection + * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx + */ +struct iwl_mvm_add_sta_key_cmd_v1 { + struct iwl_mvm_add_sta_key_common common; u8 tkip_rx_tsc_byte2; u8 reserved; __le16 tkip_rx_ttak[5]; } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_1 */ +/** + * struct iwl_mvm_add_sta_key_cmd - add/modify sta key + * @common: see &struct iwl_mvm_add_sta_key_common + * @rx_mic_key: TKIP RX unicast or multicast key + * @tx_mic_key: TKIP TX key + * @transmit_seq_cnt: TSC, transmit packet number + */ +struct iwl_mvm_add_sta_key_cmd { + struct iwl_mvm_add_sta_key_common common; + __le64 rx_mic_key; + __le64 tx_mic_key; + __le64 transmit_seq_cnt; +} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2 */ + /** * enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command * @ADD_STA_SUCCESS: operation was executed successfully diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 41fd3ba574c05..26155e2efa840 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2738,68 +2738,97 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvm_sta, - struct ieee80211_key_conf *keyconf, bool mcast, + struct ieee80211_key_conf *key, bool mcast, u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags, u8 key_offset) { - struct iwl_mvm_add_sta_key_cmd cmd = {}; + union { + struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1; + struct iwl_mvm_add_sta_key_cmd cmd; + } u = {}; __le16 key_flags; int ret; u32 status; u16 keyidx; - int i; - u8 sta_id = mvm_sta->sta_id; + u64 pn = 0; + int i, size; + bool new_api = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS); - keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & + keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & STA_KEY_FLG_KEYID_MSK; key_flags = cpu_to_le16(keyidx); key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP); - switch (keyconf->cipher) { + switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP); - cmd.tkip_rx_tsc_byte2 = tkip_iv32; - for (i = 0; i < 5; i++) - cmd.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); - memcpy(cmd.key, keyconf->key, keyconf->keylen); + if (new_api) { + memcpy((void *)&u.cmd.tx_mic_key, + &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + IWL_MIC_KEY_SIZE); + + memcpy((void *)&u.cmd.rx_mic_key, + &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + IWL_MIC_KEY_SIZE); + pn = atomic64_read(&key->tx_pn); + + } else { + u.cmd_v1.tkip_rx_tsc_byte2 = tkip_iv32; + for (i = 0; i < 5; i++) + u.cmd_v1.tkip_rx_ttak[i] = + cpu_to_le16(tkip_p1k[i]); + } + memcpy(u.cmd.common.key, key->key, key->keylen); break; case WLAN_CIPHER_SUITE_CCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_CCM); - memcpy(cmd.key, keyconf->key, keyconf->keylen); + memcpy(u.cmd.common.key, key->key, key->keylen); + if (new_api) + pn = atomic64_read(&key->tx_pn); break; case WLAN_CIPHER_SUITE_WEP104: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES); /* fall through */ case WLAN_CIPHER_SUITE_WEP40: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); - memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); + memcpy(u.cmd.common.key + 3, key->key, key->keylen); break; case WLAN_CIPHER_SUITE_GCMP_256: key_flags |= cpu_to_le16(STA_KEY_FLG_KEY_32BYTES); /* fall through */ case WLAN_CIPHER_SUITE_GCMP: key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP); - memcpy(cmd.key, keyconf->key, keyconf->keylen); + memcpy(u.cmd.common.key, key->key, key->keylen); + if (new_api) + pn = atomic64_read(&key->tx_pn); break; default: key_flags |= cpu_to_le16(STA_KEY_FLG_EXT); - memcpy(cmd.key, keyconf->key, keyconf->keylen); + memcpy(u.cmd.common.key, key->key, key->keylen); } if (mcast) key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - cmd.key_offset = key_offset; - cmd.key_flags = key_flags; - cmd.sta_id = sta_id; + u.cmd.common.key_offset = key_offset; + u.cmd.common.key_flags = key_flags; + u.cmd.common.sta_id = mvm_sta->sta_id; + + if (new_api) { + u.cmd.transmit_seq_cnt = cpu_to_le64(pn); + size = sizeof(u.cmd); + } else { + size = sizeof(u.cmd_v1); + } status = ADD_STA_SUCCESS; if (cmd_flags & CMD_ASYNC) - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, CMD_ASYNC, - sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, CMD_ASYNC, size, + &u.cmd); else - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), - &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, + &u.cmd, &status); switch (status) { case ADD_STA_SUCCESS: @@ -2952,9 +2981,14 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, struct ieee80211_key_conf *keyconf, bool mcast) { - struct iwl_mvm_add_sta_key_cmd cmd = {}; + union { + struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1; + struct iwl_mvm_add_sta_key_cmd cmd; + } u = {}; + bool new_api = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS); __le16 key_flags; - int ret; + int ret, size; u32 status; key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -2965,13 +2999,19 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, if (mcast) key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - cmd.key_flags = key_flags; - cmd.key_offset = keyconf->hw_key_idx; - cmd.sta_id = sta_id; + /* + * The fields assigned here are in the same location at the start + * of the command, so we can do this union trick. + */ + u.cmd.common.key_flags = key_flags; + u.cmd.common.key_offset = keyconf->hw_key_idx; + u.cmd.common.sta_id = sta_id; + + size = new_api ? sizeof(u.cmd) : sizeof(u.cmd_v1); status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd), - &cmd, &status); + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, &u.cmd, + &status); switch (status) { case ADD_STA_SUCCESS: From 9c36fd711c4340fff922f8a541199a67fd027e9b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 4 Jan 2017 10:49:42 +0200 Subject: [PATCH 024/201] iwlwifi: mvm: optimize reorder timeout frame releasing Currently we release up to the last expired frame. However, if there are consecutive frames after it - we can optimize it further and release them as well - until the next hole. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index d79e9c2a2654a..85f7c83995b95 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -462,6 +462,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) int i; u16 sn = 0, index = 0; bool expired = false; + bool cont = false; spin_lock(&buf->lock); @@ -473,12 +474,21 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) for (i = 0; i < buf->buf_size ; i++) { index = (buf->head_sn + i) % buf->buf_size; - if (skb_queue_empty(&buf->entries[index])) + if (skb_queue_empty(&buf->entries[index])) { + /* + * If there is a hole and the next frame didn't expire + * we want to break and not advance SN + */ + cont = false; continue; - if (!time_after(jiffies, buf->reorder_time[index] + - RX_REORDER_BUF_TIMEOUT_MQ)) + } + if (!cont && !time_after(jiffies, buf->reorder_time[index] + + RX_REORDER_BUF_TIMEOUT_MQ)) break; + expired = true; + /* continue until next hole after this expired frames */ + cont = true; sn = ieee80211_sn_add(buf->head_sn, i + 1); } From 49f7171382b55f74f84e5c2dfceca0ed3d1ac3f2 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 9 Jan 2017 12:07:16 +0200 Subject: [PATCH 025/201] iwlwifi: mvm: don't assume static queue numbers In a000 devices FW will assign the queue number. Prepare for that by getting rid of static defines and store them in variables. Enlarge to u16 since we may have up to 512 queues. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 22 +++++++------------- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 +++---- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 70b9946382735..b58ac2aa9999a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -976,7 +976,10 @@ struct iwl_mvm { #endif /* Tx queues */ - u8 aux_queue; + u16 aux_queue; + u16 probe_queue; + u16 p2p_dev_queue; + u8 first_agg_queue; u8 last_agg_queue; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index f4f957fe71d7b..600af8a31200f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -603,6 +603,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, } } else { mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; + mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE; mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 26155e2efa840..2d68cee413065 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1806,9 +1806,9 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int queue; if (vif->type == NL80211_IFTYPE_AP) - queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + queue = mvm->probe_queue; else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) - queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + queue = mvm->p2p_dev_queue; else if (WARN(1, "Missing required TXQ for adding bcast STA\n")) return -EINVAL; @@ -1836,24 +1836,18 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (mvmvif->bcast_sta.tfd_queue_msk & - BIT(IWL_MVM_DQA_AP_PROBE_RESP_QUEUE)) { - iwl_mvm_disable_txq(mvm, - IWL_MVM_DQA_AP_PROBE_RESP_QUEUE, + if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->probe_queue)) { + iwl_mvm_disable_txq(mvm, mvm->probe_queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); - mvmvif->bcast_sta.tfd_queue_msk &= - ~BIT(IWL_MVM_DQA_AP_PROBE_RESP_QUEUE); + mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->probe_queue); } - if (mvmvif->bcast_sta.tfd_queue_msk & - BIT(IWL_MVM_DQA_P2P_DEVICE_QUEUE)) { - iwl_mvm_disable_txq(mvm, - IWL_MVM_DQA_P2P_DEVICE_QUEUE, + if (mvmvif->bcast_sta.tfd_queue_msk & BIT(mvm->p2p_dev_queue)) { + iwl_mvm_disable_txq(mvm, mvm->p2p_dev_queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); - mvmvif->bcast_sta.tfd_queue_msk &= - ~BIT(IWL_MVM_DQA_P2P_DEVICE_QUEUE); + mvmvif->bcast_sta.tfd_queue_msk &= ~BIT(mvm->p2p_dev_queue); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 3f37075f4cde3..568b0793e84e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -513,20 +513,20 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, */ if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || ieee80211_is_deauth(fc)) - return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + return mvm->probe_queue; if (info->hw_queue == info->control.vif->cab_queue) return info->hw_queue; WARN_ONCE(1, "fc=0x%02x", le16_to_cpu(fc)); - return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + return mvm->probe_queue; case NL80211_IFTYPE_P2P_DEVICE: if (ieee80211_is_mgmt(fc)) - return IWL_MVM_DQA_P2P_DEVICE_QUEUE; + return mvm->p2p_dev_queue; if (info->hw_queue == info->control.vif->cab_queue) return info->hw_queue; WARN_ON_ONCE(1); - return IWL_MVM_DQA_P2P_DEVICE_QUEUE; + return mvm->p2p_dev_queue; default: WARN_ONCE(1, "Not a ctrl vif, no available queue\n"); return -1; From b9f916202997f515456c09e2c893b0dc83049d31 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 28 Sep 2016 15:56:21 +0300 Subject: [PATCH 026/201] Revert "iwlwifi: introduce trans API to get byte count table" This reverts commit 8aacf4b73fe8 ("iwlwifi: introduce trans API to get byte count table"). The commit is not needed as a better approach will be taken. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 11 ----------- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 1 - drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 -- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 -------- 4 files changed, 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0296124a7f9cf..b52804dd884f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -644,8 +644,6 @@ struct iwl_trans_ops { void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, bool shared); - dma_addr_t (*get_txq_byte_table)(struct iwl_trans *trans, int txq_id); - int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, bool freeze); @@ -1072,15 +1070,6 @@ static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, trans->ops->txq_set_shared_mode(trans, queue, shared_mode); } -static inline dma_addr_t iwl_trans_get_txq_byte_table(struct iwl_trans *trans, - int queue) -{ - /* we should never be called if the trans doesn't support it */ - BUG_ON(!trans->ops->get_txq_byte_table); - - return trans->ops->get_txq_byte_table(trans, queue); -} - static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 10937309641a5..541b969fe283a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -484,7 +484,6 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, bool configure_scd); void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, bool shared_mode); -dma_addr_t iwl_trans_pcie_get_txq_byte_table(struct iwl_trans *trans, int txq); void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index fbb0afa9de142..69f1b032260c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2897,8 +2897,6 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_disable = iwl_trans_pcie_txq_disable, .txq_enable = iwl_trans_pcie_txq_enable, - .get_txq_byte_table = iwl_trans_pcie_get_txq_byte_table, - .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 03df578bed008..a313c187524b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1424,14 +1424,6 @@ void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, txq->ampdu = !shared_mode; } -dma_addr_t iwl_trans_pcie_get_txq_byte_table(struct iwl_trans *trans, int txq) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - return trans_pcie->scd_bc_tbls.dma + - txq * sizeof(struct iwlagn_scd_bc_tbl); -} - void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, bool configure_scd) { From de74c455fd991024be76a535df4d66e96af3896e Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 29 Sep 2016 14:31:24 +0300 Subject: [PATCH 027/201] iwlwifi: pcie: remove the active field in struct iwl_txq We already have queue_used in the transport - we can use it instead. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 -- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 541b969fe283a..1ef9bb83a43f4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -237,7 +237,6 @@ struct iwl_pcie_first_tb_buf { * @stuck_timer: timer that fires if queue gets stuck * @trans_pcie: pointer back to transport (for timer) * @need_update: indicates need to update read/write index - * @active: stores if queue is active * @ampdu: true if this queue is an ampdu queue for an specific RA/TID * @wd_timeout: queue watchdog timeout (jiffies) - per queue * @frozen: tx stuck queue timer is frozen @@ -277,7 +276,6 @@ struct iwl_txq { struct iwl_trans_pcie *trans_pcie; bool need_update; bool frozen; - u8 active; bool ampdu; int block; unsigned long wd_timeout; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index a313c187524b9..66bdd2df910a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -701,7 +701,6 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } } - txq->active = false; while (!skb_queue_empty(&txq->overflow_q)) { struct sk_buff *skb = __skb_dequeue(&txq->overflow_q); @@ -932,6 +931,8 @@ void iwl_pcie_tx_free(struct iwl_trans *trans) int txq_id; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + /* Tx queues */ if (trans_pcie->txq) { for (txq_id = 0; @@ -1107,7 +1108,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, spin_lock_bh(&txq->lock); - if (!txq->active) { + if (!test_bit(txq_id, trans_pcie->queue_used)) { IWL_DEBUG_TX_QUEUES(trans, "Q %d inactive - ignoring idx %d\n", txq_id, ssn); goto out; @@ -1411,8 +1412,6 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, "Activate queue %d WrPtr: %d\n", txq_id, ssn & 0xff); } - - txq->active = true; } void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, From 82ea79660c2744c6d273862a455ca634a6c4d2ee Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 28 Dec 2016 10:04:23 +0200 Subject: [PATCH 028/201] iwlwifi: pcie: use WFPM_GP for debugging D3 flows This register is helpful for debugging D3 issues. Driver turns all bits on, and then on exit reads the updated value there. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 406ef301b8ab8..3a8aeee3b55ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -378,6 +378,7 @@ #define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078 #define RFIC_REG_RD 0xAD0470 #define WFPM_CTRL_REG 0xA03030 +#define WFPM_GP2 0xA030B4 enum { ENABLE_WFPM = BIT(31), WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 69f1b032260c2..15bf5100d0964 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1047,6 +1047,16 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, if (ret) return ret; + IWL_DEBUG_POWER(trans, "Original WFPM value = 0x%08X\n", + iwl_read_prph(trans, WFPM_GP2)); + + /* + * Set default value. On resume reading the values that were + * zeored can provide debug data on the resume flow. + * This is for debugging only and has no functional impact. + */ + iwl_write_prph(trans, WFPM_GP2, 0x01010101); + /* configure the ucode to be ready to get the secured image */ /* release CPU reset */ iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); @@ -1527,6 +1537,9 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, } } + IWL_DEBUG_POWER(trans, "WFPM value upon resume = 0x%08X\n", + iwl_read_prph(trans, WFPM_GP2)); + val = iwl_read32(trans, CSR_RESET); if (val & CSR_RESET_REG_FLAG_NEVO_RESET) *status = IWL_D3_STATUS_RESET; From 7abf6fde970cc27dda7a8f02439fd0b8a0156459 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 9 Jan 2017 11:31:39 +0100 Subject: [PATCH 029/201] iwlwifi: pcie: use iwl_get_dma_hi_addr() Use iwl_get_dma_hi_addr() instead of open-coding it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 66bdd2df910a4..9c8ab1a82b721 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -380,8 +380,7 @@ static inline void iwl_pcie_tfd_set_tb(struct iwl_trans *trans, void *tfd, u16 hi_n_len = len << 4; put_unaligned_le32(addr, &tb->lo); - if (sizeof(dma_addr_t) > sizeof(u32)) - hi_n_len |= ((addr >> 16) >> 16) & 0xF; + hi_n_len |= iwl_get_dma_hi_addr(addr); tb->hi_n_len = cpu_to_le16(hi_n_len); From bdccdb854f2fb473f2ac4a6108df3cbfcedd5a87 Mon Sep 17 00:00:00 2001 From: Golan Ben-Ami Date: Tue, 15 Nov 2016 14:45:29 +0200 Subject: [PATCH 030/201] iwlwifi: mvm: support MFUART dump in case of MFUART assert In case of a MFUART assert, get a notification from the fw that consists of the assert id and debug data. The notification may be divided to multiple chunks, depending on the size of the debug data sent to the driver, which would be up to 1KB. Get the notification, and if the debug info flag is enabled, print the debug data to the dmesg. Signed-off-by: Golan Ben-Ami Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api.h | 26 ++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 24 ++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 9 +++++++ 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 248373a0990a8..dd2bd7c3587c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -345,9 +345,10 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_ACCESS_COMPLETE = 0x0, }; -enum iwl_fmac_debug_cmds { +enum iwl_debug_cmds { LMAC_RD_WR = 0x0, UMAC_RD_WR = 0x1, + MFU_ASSERT_DUMP_NTF = 0xFE, }; /* command groups */ @@ -1238,6 +1239,25 @@ struct iwl_mfuart_load_notif { __le32 image_size; } __packed; /*MFU_LOADER_NTFY_API_S_VER_2*/ +/** + * struct iwl_mfu_assert_dump_notif - mfuart dump logs + * ( MFU_ASSERT_DUMP_NTF = 0xfe ) + * @assert_id: mfuart assert id that cause the notif + * @curr_reset_num: number of asserts since uptime + * @index_num: current chunk id + * @parts_num: total number of chunks + * @data_size: number of data bytes sent + * @data: data buffer + */ +struct iwl_mfu_assert_dump_notif { + __le32 assert_id; + __le32 curr_reset_num; + __le16 index_num; + __le16 parts_num; + __le32 data_size; + __le32 data[0]; +} __packed; /*MFU_DUMP_ASSERT_API_S_VER_1*/ + /** * struct iwl_set_calib_default_cmd - set default value for calibration. * ( SET_CALIB_DEFAULT_CMD = 0x8e ) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 45cb4f476e761..286f186097295 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -271,6 +272,27 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) return 0; } +void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mfu_assert_dump_notif *mfu_dump_notif = (void *)pkt->data; + __le32 *dump_data = mfu_dump_notif->data; + int n_words = le32_to_cpu(mfu_dump_notif->data_size) / sizeof(__le32); + int i; + + if (mfu_dump_notif->index_num == 0) + IWL_INFO(mvm, "MFUART assert id 0x%x occurred\n", + le32_to_cpu(mfu_dump_notif->assert_id)); + + for (i = 0; i < n_words; i++) + IWL_DEBUG_INFO(mvm, + "MFUART assert dump, dword %u: 0x%08x\n", + le16_to_cpu(mfu_dump_notif->index_num) * + n_words + i, + le32_to_cpu(dump_data[i])); +} + static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b58ac2aa9999a..b3f67fe982032 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1395,6 +1395,8 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 600af8a31200f..72afccfe42827 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -302,6 +302,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_SYNC), RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER_GRP(DEBUG_GROUP, MFU_ASSERT_DUMP_NTF, + iwl_mvm_mfu_assert_dump_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, iwl_mvm_rx_stored_beacon_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, @@ -460,6 +462,13 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(RX_QUEUES_NOTIFICATION), }; +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_debug_names[] = { + HCMD_NAME(MFU_ASSERT_DUMP_NTF), +}; + /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ From 1ea423b0e047757dea80d5d968a25aa44af51273 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 11 Apr 2017 14:46:35 +0300 Subject: [PATCH 031/201] iwlwifi: remove unnecessary dev_cmd_headroom parameter We don't need this parameter anymore, since we always pass 0 anyway. Remove it from the structure and from all the relevant functions. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 7 ++----- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 17 +++++------------ drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index d42cab2910257..0bde26bab15df 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -70,8 +70,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, const struct iwl_cfg *cfg, - const struct iwl_trans_ops *ops, - size_t dev_cmd_headroom) + const struct iwl_trans_ops *ops) { struct iwl_trans *trans; #ifdef CONFIG_LOCKDEP @@ -90,15 +89,13 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, trans->dev = dev; trans->cfg = cfg; trans->ops = ops; - trans->dev_cmd_headroom = dev_cmd_headroom; trans->num_rx_queues = 1; snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), "iwl_cmd_pool:%s", dev_name(trans->dev)); trans->dev_cmd_pool = kmem_cache_create(trans->dev_cmd_pool_name, - sizeof(struct iwl_device_cmd) - + trans->dev_cmd_headroom, + sizeof(struct iwl_device_cmd), sizeof(void *), SLAB_HWCACHE_ALIGN, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index b52804dd884f3..1b4b62ede2c4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -772,9 +772,6 @@ enum iwl_plat_pm_mode { * the transport must set this before calling iwl_drv_start() * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. - * @dev_cmd_headroom: room needed for the transport's private use before the - * device_cmd for Tx - for internal use only - * The user should use iwl_trans_{alloc,free}_tx_cmd. * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before * starting the firmware, used for tracing * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the @@ -825,7 +822,6 @@ struct iwl_trans { /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; - size_t dev_cmd_headroom; char dev_cmd_pool_name[50]; struct dentry *dbgfs_dir; @@ -998,13 +994,13 @@ iwl_trans_dump_data(struct iwl_trans *trans, static inline struct iwl_device_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { - u8 *dev_cmd_ptr = kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); + struct iwl_device_cmd *dev_cmd_ptr = + kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC); if (unlikely(dev_cmd_ptr == NULL)) return NULL; - return (struct iwl_device_cmd *) - (dev_cmd_ptr + trans->dev_cmd_headroom); + return dev_cmd_ptr; } int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); @@ -1012,9 +1008,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, struct iwl_device_cmd *dev_cmd) { - u8 *dev_cmd_ptr = (u8 *)dev_cmd - trans->dev_cmd_headroom; - - kmem_cache_free(trans->dev_cmd_pool, dev_cmd_ptr); + kmem_cache_free(trans->dev_cmd_pool, dev_cmd); } static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, @@ -1237,8 +1231,7 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans) struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, const struct iwl_cfg *cfg, - const struct iwl_trans_ops *ops, - size_t dev_cmd_headroom); + const struct iwl_trans_ops *ops); void iwl_trans_free(struct iwl_trans *trans); /***************************************************** diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 15bf5100d0964..b362779b66f43 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2948,7 +2948,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, return ERR_PTR(ret); trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), - &pdev->dev, cfg, &trans_ops_pcie, 0); + &pdev->dev, cfg, &trans_ops_pcie); if (!trans) return ERR_PTR(-ENOMEM); From 623e7766be907d9c20af334e25f98005c75b5d32 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 28 Sep 2016 15:52:21 +0300 Subject: [PATCH 032/201] iwlwifi: pcie: introduce split point to a000 devices a000 devices are going to have a lot of flows simplified and changed: init flow, RX, TX, and more. This, combined with the fact that code is already very complicated due to backward compatibility - introduce a split that will enable to introduce simplified version of functions. Shared ops are moved to a macro, while functions that will be updated in the next patches are defined twice for now. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 3 +- .../net/wireless/intel/iwlwifi/iwl-config.h | 4 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 85 +++++++++++++------ 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 20739e92aef6c..df4e8714d627c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -121,7 +121,8 @@ static const struct iwl_ht_params iwl_a000_ht_params = { .vht_mu_mimo_supported = true, \ .mac_addr_from_csr = true, \ .use_tfh = true, \ - .rf_id = true + .rf_id = true, \ + .gen2 = true const struct iwl_cfg iwla000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC a000", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 852963487bd91..717e089ff036f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -323,6 +323,7 @@ struct iwl_pwr_tx_backoff { * @vht_mu_mimo_supported: VHT MU-MIMO support * @rf_id: need to read rf_id to determine the firmware image * @integrated: discrete or integrated + * @gen2: a000 and on transport operation * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -368,7 +369,8 @@ struct iwl_cfg { vht_mu_mimo_supported:1, rf_id:1, integrated:1, - use_tfh:1; + use_tfh:1, + gen2:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index b362779b66f43..16c8b37bf6d7e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2887,20 +2887,64 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) } #endif /* CONFIG_PM_SLEEP */ +#define IWL_TRANS_COMMON_OPS \ + .op_mode_leave = iwl_trans_pcie_op_mode_leave, \ + .write8 = iwl_trans_pcie_write8, \ + .write32 = iwl_trans_pcie_write32, \ + .read32 = iwl_trans_pcie_read32, \ + .read_prph = iwl_trans_pcie_read_prph, \ + .write_prph = iwl_trans_pcie_write_prph, \ + .read_mem = iwl_trans_pcie_read_mem, \ + .write_mem = iwl_trans_pcie_write_mem, \ + .configure = iwl_trans_pcie_configure, \ + .set_pmi = iwl_trans_pcie_set_pmi, \ + .grab_nic_access = iwl_trans_pcie_grab_nic_access, \ + .release_nic_access = iwl_trans_pcie_release_nic_access, \ + .set_bits_mask = iwl_trans_pcie_set_bits_mask, \ + .ref = iwl_trans_pcie_ref, \ + .unref = iwl_trans_pcie_unref, \ + .dump_data = iwl_trans_pcie_dump_data, \ + .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, \ + .d3_suspend = iwl_trans_pcie_d3_suspend, \ + .d3_resume = iwl_trans_pcie_d3_resume + +#ifdef CONFIG_PM_SLEEP +#define IWL_TRANS_PM_OPS \ + .suspend = iwl_trans_pcie_suspend, \ + .resume = iwl_trans_pcie_resume, +#else +#define IWL_TRANS_PM_OPS +#endif /* CONFIG_PM_SLEEP */ + static const struct iwl_trans_ops trans_ops_pcie = { + IWL_TRANS_COMMON_OPS, + IWL_TRANS_PM_OPS .start_hw = iwl_trans_pcie_start_hw, - .op_mode_leave = iwl_trans_pcie_op_mode_leave, .fw_alive = iwl_trans_pcie_fw_alive, .start_fw = iwl_trans_pcie_start_fw, .stop_device = iwl_trans_pcie_stop_device, - .d3_suspend = iwl_trans_pcie_d3_suspend, - .d3_resume = iwl_trans_pcie_d3_resume, + .send_cmd = iwl_trans_pcie_send_hcmd, + + .tx = iwl_trans_pcie_tx, + .reclaim = iwl_trans_pcie_reclaim, -#ifdef CONFIG_PM_SLEEP - .suspend = iwl_trans_pcie_suspend, - .resume = iwl_trans_pcie_resume, -#endif /* CONFIG_PM_SLEEP */ + .txq_disable = iwl_trans_pcie_txq_disable, + .txq_enable = iwl_trans_pcie_txq_enable, + + .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + + .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, + .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, +}; + +static const struct iwl_trans_ops trans_ops_pcie_gen2 = { + IWL_TRANS_COMMON_OPS, + IWL_TRANS_PM_OPS + .start_hw = iwl_trans_pcie_start_hw, + .fw_alive = iwl_trans_pcie_fw_alive, + .start_fw = iwl_trans_pcie_start_fw, + .stop_device = iwl_trans_pcie_stop_device, .send_cmd = iwl_trans_pcie_send_hcmd, @@ -2912,27 +2956,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, - .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, - - .write8 = iwl_trans_pcie_write8, - .write32 = iwl_trans_pcie_write32, - .read32 = iwl_trans_pcie_read32, - .read_prph = iwl_trans_pcie_read_prph, - .write_prph = iwl_trans_pcie_write_prph, - .read_mem = iwl_trans_pcie_read_mem, - .write_mem = iwl_trans_pcie_write_mem, - .configure = iwl_trans_pcie_configure, - .set_pmi = iwl_trans_pcie_set_pmi, - .grab_nic_access = iwl_trans_pcie_grab_nic_access, - .release_nic_access = iwl_trans_pcie_release_nic_access, - .set_bits_mask = iwl_trans_pcie_set_bits_mask, - - .ref = iwl_trans_pcie_ref, - .unref = iwl_trans_pcie_unref, - - .dump_data = iwl_trans_pcie_dump_data, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -2947,8 +2972,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), - &pdev->dev, cfg, &trans_ops_pcie); + if (cfg->gen2) + trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), + &pdev->dev, cfg, &trans_ops_pcie_gen2); + else + trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), + &pdev->dev, cfg, &trans_ops_pcie); if (!trans) return ERR_PTR(-ENOMEM); From eda50cde58de7368f982e3906090fc033ecb9360 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 28 Sep 2016 17:16:53 +0300 Subject: [PATCH 033/201] iwlwifi: pcie: add context information support Context information structure is going to be used in a000 devices for firmware self init. The self init includes firmware self loading from DRAM by ROM. This means the TFH relevant firmware loading can be cleaned up. The firmware loading includes the paging memory as well, so op mode can stop initializing the paging and sending the DRAM_BLOCK_CMD. Firmware is doing RFH, TFH and SCD configuration, while driver only fills the required configurations and addresses in the context information structure. The only remaining access to RFH is the write pointer, which is updated upon alive interrupt after FW configured the RFH. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 1 + .../wireless/intel/iwlwifi/iwl-context-info.h | 203 +++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 4 + drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 1 + .../wireless/intel/iwlwifi/pcie/ctxt-info.c | 274 ++++++++++++++++++ .../wireless/intel/iwlwifi/pcie/internal.h | 50 +++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 45 ++- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 226 +++++++++++++++ .../net/wireless/intel/iwlwifi/pcie/trans.c | 60 +--- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 78 +++-- 10 files changed, 867 insertions(+), 75 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/iwl-context-info.h create mode 100644 drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c create mode 100644 drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 92e611841200d..b27bcac8f5db4 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -7,6 +7,7 @@ iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o +iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o iwlwifi-objs += iwl-trans.o diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h new file mode 100644 index 0000000000000..b870c09867449 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h @@ -0,0 +1,203 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_context_info_file_h__ +#define __iwl_context_info_file_h__ + +/* maximmum number of DRAM map entries supported by FW */ +#define IWL_MAX_DRAM_ENTRY 64 +#define CSR_CTXT_INFO_BA 0x40 + +/** + * enum iwl_context_info_flags - Context information control flags + * @IWL_CTXT_INFO_AUTO_FUNC_INIT: If set, FW will not wait before interrupting + * the init done for driver command that configures several system modes + * @IWL_CTXT_INFO_EARLY_DEBUG: enable early debug + * @IWL_CTXT_INFO_ENABLE_CDMP: enable core dump + * @IWL_CTXT_INFO_RB_SIZE_4K: Use 4K RB size (the default is 2K) + * @IWL_CTXT_INFO_RB_CB_SIZE_POS: position of the RBD Cyclic Buffer Size + * exponent, the actual size is 2**value, valid sizes are 8-2048. + * The value is four bits long. Maximum valid exponent is 12 + * @IWL_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the + * default is short format - not supported by the driver) + */ +enum iwl_context_info_flags { + IWL_CTXT_INFO_AUTO_FUNC_INIT = BIT(0), + IWL_CTXT_INFO_EARLY_DEBUG = BIT(1), + IWL_CTXT_INFO_ENABLE_CDMP = BIT(2), + IWL_CTXT_INFO_RB_SIZE_4K = BIT(3), + IWL_CTXT_INFO_RB_CB_SIZE_POS = 4, + IWL_CTXT_INFO_TFD_FORMAT_LONG = BIT(8), +}; + +/* + * struct iwl_context_info_version - version structure + * @mac_id: SKU and revision id + * @version: context information version id + * @size: the size of the context information in DWs + */ +struct iwl_context_info_version { + __le16 mac_id; + __le16 version; + __le16 size; + __le16 reserved; +} __packed; + +/* + * struct iwl_context_info_control - version structure + * @control_flags: context information flags see &enum iwl_context_info_flags + */ +struct iwl_context_info_control { + __le32 control_flags; + __le32 reserved; +} __packed; + +/* + * struct iwl_context_info_dram - images DRAM map + * each entry in the map represents a DRAM chunk of up to 32 KB + * @umac_img: UMAC image DRAM map + * @lmac_img: LMAC image DRAM map + * @virtual_img: paged image DRAM map + */ +struct iwl_context_info_dram { + __le64 umac_img[IWL_MAX_DRAM_ENTRY]; + __le64 lmac_img[IWL_MAX_DRAM_ENTRY]; + __le64 virtual_img[IWL_MAX_DRAM_ENTRY]; +} __packed; + +/* + * struct iwl_context_info_rbd_cfg - RBDs configuration + * @free_rbd_addr: default queue free RB CB base address + * @used_rbd_addr: default queue used RB CB base address + * @status_wr_ptr: default queue used RB status write pointer + */ +struct iwl_context_info_rbd_cfg { + __le64 free_rbd_addr; + __le64 used_rbd_addr; + __le64 status_wr_ptr; +} __packed; + +/* + * struct iwl_context_info_hcmd_cfg - command queue configuration + * @cmd_queue_addr: address of command queue + * @cmd_queue_size: number of entries + */ +struct iwl_context_info_hcmd_cfg { + __le64 cmd_queue_addr; + u8 cmd_queue_size; + u8 reserved[7]; +} __packed; + +/* + * struct iwl_context_info_dump_cfg - Core Dump configuration + * @core_dump_addr: core dump (debug DRAM address) start address + * @core_dump_size: size, in DWs + */ +struct iwl_context_info_dump_cfg { + __le64 core_dump_addr; + __le32 core_dump_size; + __le32 reserved; +} __packed; + +/* + * struct iwl_context_info_pnvm_cfg - platform NVM data configuration + * @platform_nvm_addr: Platform NVM data start address + * @platform_nvm_size: size in DWs + */ +struct iwl_context_info_pnvm_cfg { + __le64 platform_nvm_addr; + __le32 platform_nvm_size; + __le32 reserved; +} __packed; + +/* + * struct iwl_context_info_early_dbg_cfg - early debug configuration for + * dumping DRAM addresses + * @early_debug_addr: early debug start address + * @early_debug_size: size in DWs + */ +struct iwl_context_info_early_dbg_cfg { + __le64 early_debug_addr; + __le32 early_debug_size; + __le32 reserved; +} __packed; + +/* + * struct iwl_context_info - device INIT configuration + * @version: version information of context info and HW + * @control: control flags of FH configurations + * @rbd_cfg: default RX queue configuration + * @hcmd_cfg: command queue configuration + * @dump_cfg: core dump data + * @edbg_cfg: early debug configuration + * @pnvm_cfg: platform nvm configuration + * @dram: firmware image addresses in DRAM + */ +struct iwl_context_info { + struct iwl_context_info_version version; + struct iwl_context_info_control control; + __le64 reserved0; + struct iwl_context_info_rbd_cfg rbd_cfg; + struct iwl_context_info_hcmd_cfg hcmd_cfg; + __le32 reserved1[4]; + struct iwl_context_info_dump_cfg dump_cfg; + struct iwl_context_info_early_dbg_cfg edbg_cfg; + struct iwl_context_info_pnvm_cfg pnvm_cfg; + __le32 reserved2[16]; + struct iwl_context_info_dram dram; + __le32 reserved3[16]; +} __packed; + +int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, const struct fw_img *fw); +void iwl_pcie_ctxt_info_free(struct iwl_trans *trans); +void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans); + +#endif /* __iwl_context_info_file_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 361fc25e8618c..62f9fe926d781 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -614,6 +614,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define RX_POOL_SIZE (MQ_RX_NUM_RBDS + \ IWL_MAX_RX_HW_QUEUES * \ (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC)) +/* cb size is the exponent */ +#define RX_QUEUE_CB_SIZE(x) ilog2(x) #define RX_QUEUE_SIZE 256 #define RX_QUEUE_MASK 255 @@ -639,6 +641,8 @@ struct iwl_rb_status { #define TFD_QUEUE_SIZE_MAX (256) +/* cb size is the exponent - 3 */ +#define TFD_QUEUE_CB_SIZE(x) (ilog2(x) - 3) #define TFD_QUEUE_SIZE_BC_DUP (64) #define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) #define IWL_TX_DMA_MASK DMA_BIT_MASK(36) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 3a8aeee3b55ad..bb7e0d642981d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -309,6 +309,7 @@ * Note this address is cleared after MAC reset. */ #define UREG_UCODE_LOAD_STATUS (0xa05c40) +#define UREG_CPU_INIT_RUN (0xa05c44) #define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78) #define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c new file mode 100644 index 0000000000000..312ee0481ec57 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include "iwl-trans.h" +#include "iwl-fh.h" +#include "iwl-context-info.h" +#include "internal.h" +#include "iwl-prph.h" + +static int iwl_pcie_get_num_sections(const struct fw_img *fw, + int start) +{ + int i = 0; + + while (start < fw->num_sec && + fw->sec[start].offset != CPU1_CPU2_SEPARATOR_SECTION && + fw->sec[start].offset != PAGING_SEPARATOR_SECTION) { + start++; + i++; + } + + return i; +} + +static int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans *trans, + const struct fw_desc *sec, + struct iwl_dram_data *dram) +{ + dram->block = dma_alloc_coherent(trans->dev, sec->len, + &dram->physical, + GFP_KERNEL); + if (!dram->block) + return -ENOMEM; + + dram->size = sec->len; + memcpy(dram->block, sec->data, sec->len); + + return 0; +} + +static void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + int i; + + if (!dram->fw) { + WARN_ON(dram->fw_cnt); + return; + } + + for (i = 0; i < dram->fw_cnt; i++) + dma_free_coherent(trans->dev, dram->fw[i].size, + dram->fw[i].block, dram->fw[i].physical); + + kfree(dram->fw); + dram->fw_cnt = 0; +} + +void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + int i; + + if (!dram->paging) { + WARN_ON(dram->paging_cnt); + return; + } + + /* free paging*/ + for (i = 0; i < dram->paging_cnt; i++) + dma_free_coherent(trans->dev, dram->paging[i].size, + dram->paging[i].block, + dram->paging[i].physical); + + kfree(dram->paging); + dram->paging_cnt = 0; +} + +static int iwl_pcie_ctxt_info_init_fw_sec(struct iwl_trans *trans, + const struct fw_img *fw, + struct iwl_context_info *ctxt_info) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + struct iwl_context_info_dram *ctxt_dram = &ctxt_info->dram; + int i, ret, lmac_cnt, umac_cnt, paging_cnt; + + lmac_cnt = iwl_pcie_get_num_sections(fw, 0); + /* add 1 due to separator */ + umac_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + 1); + /* add 2 due to separators */ + paging_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + umac_cnt + 2); + + dram->fw = kcalloc(umac_cnt + lmac_cnt, sizeof(*dram->fw), GFP_KERNEL); + if (!dram->fw) + return -ENOMEM; + dram->paging = kcalloc(paging_cnt, sizeof(*dram->paging), GFP_KERNEL); + if (!dram->paging) + return -ENOMEM; + + /* initialize lmac sections */ + for (i = 0; i < lmac_cnt; i++) { + ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[i], + &dram->fw[dram->fw_cnt]); + if (ret) + return ret; + ctxt_dram->lmac_img[i] = + cpu_to_le64(dram->fw[dram->fw_cnt].physical); + dram->fw_cnt++; + } + + /* initialize umac sections */ + for (i = 0; i < umac_cnt; i++) { + /* access FW with +1 to make up for lmac separator */ + ret = iwl_pcie_ctxt_info_alloc_dma(trans, + &fw->sec[dram->fw_cnt + 1], + &dram->fw[dram->fw_cnt]); + if (ret) + return ret; + ctxt_dram->umac_img[i] = + cpu_to_le64(dram->fw[dram->fw_cnt].physical); + dram->fw_cnt++; + } + + /* + * Initialize paging. + * Paging memory isn't stored in dram->fw as the umac and lmac - it is + * stored separately. + * This is since the timing of its release is different - + * while fw memory can be released on alive, the paging memory can be + * freed only when the device goes down. + * Given that, the logic here in accessing the fw image is a bit + * different - fw_cnt isn't changing so loop counter is added to it. + */ + for (i = 0; i < paging_cnt; i++) { + /* access FW with +2 to make up for lmac & umac separators */ + int fw_idx = dram->fw_cnt + i + 2; + + ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[fw_idx], + &dram->paging[i]); + if (ret) + return ret; + + ctxt_dram->virtual_img[i] = + cpu_to_le64(dram->paging[i].physical); + dram->paging_cnt++; + } + + return 0; +} + +int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, + const struct fw_img *fw) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_context_info *ctxt_info; + struct iwl_context_info_rbd_cfg *rx_cfg; + u32 control_flags = 0; + int ret; + + ctxt_info = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info), + &trans_pcie->ctxt_info_dma_addr, + GFP_KERNEL); + if (!ctxt_info) + return -ENOMEM; + + ctxt_info->version.version = 0; + ctxt_info->version.mac_id = + cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV)); + /* size is in DWs */ + ctxt_info->version.size = cpu_to_le16(sizeof(*ctxt_info) / 4); + + BUILD_BUG_ON(RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) > 0xF); + control_flags = IWL_CTXT_INFO_RB_SIZE_4K | + IWL_CTXT_INFO_TFD_FORMAT_LONG | + RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE) << + IWL_CTXT_INFO_RB_CB_SIZE_POS; + ctxt_info->control.control_flags = cpu_to_le32(control_flags); + + /* initialize RX default queue */ + rx_cfg = &ctxt_info->rbd_cfg; + rx_cfg->free_rbd_addr = cpu_to_le64(trans_pcie->rxq->bd_dma); + rx_cfg->used_rbd_addr = cpu_to_le64(trans_pcie->rxq->used_bd_dma); + rx_cfg->status_wr_ptr = cpu_to_le64(trans_pcie->rxq->rb_stts_dma); + + /* initialize TX command queue */ + ctxt_info->hcmd_cfg.cmd_queue_addr = + cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue].dma_addr); + ctxt_info->hcmd_cfg.cmd_queue_size = + TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX); + + /* allocate ucode sections in dram and set addresses */ + ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info); + if (ret) + return ret; + + trans_pcie->ctxt_info = ctxt_info; + + iwl_enable_interrupts(trans); + + /* kick FW self load */ + iwl_write64(trans, CSR_CTXT_INFO_BA, trans_pcie->ctxt_info_dma_addr); + iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1); + + /* Context info will be released upon alive or failure to get one */ + + return 0; +} + +void iwl_pcie_ctxt_info_free(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->ctxt_info) + return; + + dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info), + trans_pcie->ctxt_info, + trans_pcie->ctxt_info_dma_addr); + trans_pcie->ctxt_info_dma_addr = 0; + trans_pcie->ctxt_info = NULL; + + iwl_pcie_ctxt_info_free_fw_img(trans); +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 1ef9bb83a43f4..98c1308eab0da 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -2,7 +2,7 @@ * * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -312,12 +312,44 @@ enum iwl_shared_irq_flags { IWL_SHARED_IRQ_FIRST_RSS = BIT(1), }; +/** + * struct iwl_dram_data + * @physical: page phy pointer + * @block: pointer to the allocated block/page + * @size: size of the block/page + */ +struct iwl_dram_data { + dma_addr_t physical; + void *block; + int size; +}; + +/** + * struct iwl_self_init_dram - dram data used by self init process + * @fw: lmac and umac dram data + * @fw_cnt: total number of items in array + * @paging: paging dram data + * @paging_cnt: total number of items in array + */ +struct iwl_self_init_dram { + struct iwl_dram_data *fw; + int fw_cnt; + struct iwl_dram_data *paging; + int paging_cnt; +}; + /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues * @global_table: table mapping received VID from hw to rxb * @rba: allocator for RX replenishing + * @ctxt_info: context information for FW self init + * @ctxt_info_dma_addr: dma addr of context information + * @init_dram: DRAM data of firmware image (including paging). + * Context information addresses will be taken from here. + * This is driver's local copy for keeping track of size and + * count for allocating and freeing the memory. * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @scd_bc_tbls: pointer to the byte count table of the scheduler @@ -355,6 +387,9 @@ struct iwl_trans_pcie { struct iwl_rx_mem_buffer rx_pool[RX_POOL_SIZE]; struct iwl_rx_mem_buffer *global_table[RX_POOL_SIZE]; struct iwl_rb_allocator rba; + struct iwl_context_info *ctxt_info; + dma_addr_t ctxt_info_dma_addr; + struct iwl_self_init_dram init_dram; struct iwl_trans *trans; struct net_device napi_dev; @@ -452,6 +487,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); * RX ******************************************************/ int iwl_pcie_rx_init(struct iwl_trans *trans); +int iwl_pcie_gen2_rx_init(struct iwl_trans *trans); irqreturn_t iwl_pcie_msix_isr(int irq, void *data); irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id); @@ -472,6 +508,7 @@ void iwl_pcie_disable_ict(struct iwl_trans *trans); * TX / HCMD ******************************************************/ int iwl_pcie_tx_init(struct iwl_trans *trans); +int iwl_pcie_gen2_tx_init(struct iwl_trans *trans); void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); @@ -716,4 +753,15 @@ int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans); void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable); +/* common functions that are used by gen2 transport */ +void iwl_pcie_apm_config(struct iwl_trans *trans); +int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); +void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); +bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); + +/* transport gen 2 exported functions */ +int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, + const struct fw_img *fw, bool run_in_rfkill); +void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr); + #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 17806d82f3a3d..c6178d36698c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -2,7 +2,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -880,7 +880,7 @@ static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) return 0; } -int iwl_pcie_rx_init(struct iwl_trans *trans) +static int _iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *def_rxq; @@ -958,20 +958,40 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq); + return 0; +} + +int iwl_pcie_rx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret = _iwl_pcie_rx_init(trans); + + if (ret) + return ret; + if (trans->cfg->mq_rx_supported) iwl_pcie_rx_mq_hw_init(trans); else - iwl_pcie_rx_hw_init(trans, def_rxq); + iwl_pcie_rx_hw_init(trans, trans_pcie->rxq); - iwl_pcie_rxq_restock(trans, def_rxq); + iwl_pcie_rxq_restock(trans, trans_pcie->rxq); - spin_lock(&def_rxq->lock); - iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq); - spin_unlock(&def_rxq->lock); + spin_lock(&trans_pcie->rxq->lock); + iwl_pcie_rxq_inc_wr_ptr(trans, trans_pcie->rxq); + spin_unlock(&trans_pcie->rxq->lock); return 0; } +int iwl_pcie_gen2_rx_init(struct iwl_trans *trans) +{ + /* + * We don't configure the RFH. + * Restock will be done at alive, after firmware configured the RFH. + */ + return _iwl_pcie_rx_init(trans); +} + void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1594,6 +1614,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) if (inta & CSR_INT_BIT_ALIVE) { IWL_DEBUG_ISR(trans, "Alive interrupt\n"); isr_stats->alive++; + if (trans->cfg->gen2) { + /* + * We can restock, since firmware configured + * the RFH + */ + iwl_pcie_rxmq_restock(trans, trans_pcie->rxq); + } } } @@ -1930,6 +1957,10 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) { IWL_DEBUG_ISR(trans, "Alive interrupt\n"); isr_stats->alive++; + if (trans->cfg->gen2) { + /* We can restock, since firmware configured the RFH */ + iwl_pcie_rxmq_restock(trans, trans_pcie->rxq); + } } /* uCode wakes up after power-down sleep */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c new file mode 100644 index 0000000000000..302310dfef9ee --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -0,0 +1,226 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-trans.h" +#include "iwl-context-info.h" +#include "internal.h" + +/* + * Start up NIC's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop()) + * NOTE: This does not load uCode nor start the embedded processor + */ +static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) +{ + int ret = 0; + + IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); + + /* + * Use "set_bit" below rather than "write", to preserve any hardware + * bits already set by default after reset. + */ + + /* + * Disable L0s without affecting L1; + * don't wait for ICH L0s (ICH bug W/A) + */ + iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Enable HAP INTA (interrupt from management bus) to + * wake device's PCI Express link L1a -> L0s + */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); + + iwl_pcie_apm_config(trans); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO(trans, "Failed to init the card\n"); + return ret; + } + + set_bit(STATUS_DEVICE_ENABLED, &trans->status); + + return 0; +} + +static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + /* TODO: most of the logic can be removed in A0 - but not in Z0 */ + spin_lock(&trans_pcie->irq_lock); + iwl_pcie_gen2_apm_init(trans); + spin_unlock(&trans_pcie->irq_lock); + + iwl_op_mode_nic_config(trans->op_mode); + + /* Allocate the RX queue, or reset if it is already allocated */ + if (iwl_pcie_gen2_rx_init(trans)) + return -ENOMEM; + + /* Allocate or reset and init all Tx and Command queues */ + if (iwl_pcie_gen2_tx_init(trans)) + return -ENOMEM; + + /* enable shadow regs in HW */ + iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); + IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n"); + + return 0; +} + +void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + iwl_pcie_reset_ict(trans); + + /* make sure all queue are not stopped/used */ + memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + + /* now that we got alive we can free the fw image & the context info. + * paging memory cannot be freed included since FW will still use it + */ + iwl_pcie_ctxt_info_free(trans); +} + +int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, + const struct fw_img *fw, bool run_in_rfkill) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool hw_rfkill; + int ret; + + /* This may fail if AMT took ownership of the device */ + if (iwl_pcie_prepare_card_hw(trans)) { + IWL_WARN(trans, "Exit HW not ready\n"); + ret = -EIO; + goto out; + } + + iwl_enable_rfkill_int(trans); + + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + + /* + * We enabled the RF-Kill interrupt and the handler may very + * well be running. Disable the interrupts to make sure no other + * interrupt can be fired. + */ + iwl_disable_interrupts(trans); + + /* Make sure it finished running */ + iwl_pcie_synchronize_irqs(trans); + + mutex_lock(&trans_pcie->mutex); + + /* If platform's RF_KILL switch is NOT set to KILL */ + hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + if (hw_rfkill && !run_in_rfkill) { + ret = -ERFKILL; + goto out; + } + + /* Someone called stop_device, don't try to start_fw */ + if (trans_pcie->is_down) { + IWL_WARN(trans, + "Can't start_fw since the HW hasn't been started\n"); + ret = -EIO; + goto out; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + + ret = iwl_pcie_gen2_nic_init(trans); + if (ret) { + IWL_ERR(trans, "Unable to init nic\n"); + goto out; + } + + if (iwl_pcie_ctxt_info_init(trans, fw)) + return -ENOMEM; + + /* re-check RF-Kill state since we may have missed the interrupt */ + hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + if (hw_rfkill && !run_in_rfkill) + ret = -ERFKILL; + +out: + mutex_unlock(&trans_pcie->mutex); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 16c8b37bf6d7e..361f0b0a6f42c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -80,6 +80,7 @@ #include "iwl-prph.h" #include "iwl-scd.h" #include "iwl-agn-hw.h" +#include "iwl-context-info.h" #include "iwl-fw-error-dump.h" #include "internal.h" #include "iwl-fh.h" @@ -201,7 +202,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -static void iwl_pcie_apm_config(struct iwl_trans *trans) +void iwl_pcie_apm_config(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u16 lctl; @@ -567,7 +568,7 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) } /* Note: returns standard 0/-ERROR code */ -static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) +int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) { int ret; int t = 0; @@ -636,29 +637,6 @@ static void iwl_pcie_load_firmware_chunk_fh(struct iwl_trans *trans, FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); } -static void iwl_pcie_load_firmware_chunk_tfh(struct iwl_trans *trans, - u32 dst_addr, dma_addr_t phy_addr, - u32 byte_cnt) -{ - /* Stop DMA channel */ - iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, 0); - - /* Configure SRAM address */ - iwl_write32(trans, TFH_SRV_DMA_CHNL0_SRAM_ADDR, - dst_addr); - - /* Configure DRAM address - 64 bit */ - iwl_write64(trans, TFH_SRV_DMA_CHNL0_DRAM_ADDR, phy_addr); - - /* Configure byte count to transfer */ - iwl_write32(trans, TFH_SRV_DMA_CHNL0_BC, byte_cnt); - - /* Enable the DRAM2SRAM to start */ - iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, TFH_SRV_DMA_SNOOP | - TFH_SRV_DMA_TO_DRIVER | - TFH_SRV_DMA_START); -} - static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr, dma_addr_t phy_addr, u32 byte_cnt) @@ -672,12 +650,8 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, if (!iwl_trans_grab_nic_access(trans, &flags)) return -EIO; - if (trans->cfg->use_tfh) - iwl_pcie_load_firmware_chunk_tfh(trans, dst_addr, phy_addr, - byte_cnt); - else - iwl_pcie_load_firmware_chunk_fh(trans, dst_addr, phy_addr, - byte_cnt); + iwl_pcie_load_firmware_chunk_fh(trans, dst_addr, phy_addr, + byte_cnt); iwl_trans_release_nic_access(trans, &flags); ret = wait_event_timeout(trans_pcie->ucode_write_waitq, @@ -828,15 +802,10 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, return ret; /* Notify ucode of loaded section number and status */ - if (trans->cfg->use_tfh) { - val = iwl_read_prph(trans, UREG_UCODE_LOAD_STATUS); - val = val | (sec_num << shift_param); - iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS, val); - } else { - val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS); - val = val | (sec_num << shift_param); - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); - } + val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS); + val = val | (sec_num << shift_param); + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); + sec_num = (sec_num << 1) | 0x1; } @@ -1072,7 +1041,7 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, &first_ucode_section); } -static bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans) +bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans) { bool hw_rfkill = iwl_is_rfkill_set(trans); @@ -1244,6 +1213,9 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) } } + iwl_pcie_ctxt_info_free_paging(trans); + iwl_pcie_ctxt_info_free(trans); + /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1309,7 +1281,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) iwl_pcie_prepare_card_hw(trans); } -static void iwl_pcie_synchronize_irqs(struct iwl_trans *trans) +void iwl_pcie_synchronize_irqs(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2942,8 +2914,8 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { IWL_TRANS_COMMON_OPS, IWL_TRANS_PM_OPS .start_hw = iwl_trans_pcie_start_hw, - .fw_alive = iwl_trans_pcie_fw_alive, - .start_fw = iwl_trans_pcie_start_fw, + .fw_alive = iwl_trans_pcie_gen2_fw_alive, + .start_fw = iwl_trans_pcie_gen2_start_fw, .stop_device = iwl_trans_pcie_stop_device, .send_cmd = iwl_trans_pcie_send_hcmd, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9c8ab1a82b721..b3ac1fb510095 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2,7 +2,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -612,18 +612,6 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, __skb_queue_head_init(&txq->overflow_q); - /* - * Tell nic where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * Circular buffer (TFD queue in DRAM) physical base address */ - if (trans->cfg->use_tfh) - iwl_write_direct64(trans, - FH_MEM_CBBC_QUEUE(trans, txq_id), - txq->dma_addr); - else - iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), - txq->dma_addr >> 8); - return 0; } @@ -775,9 +763,6 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); - if (trans->cfg->use_tfh) - return; - trans_pcie->scd_base_addr = iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); @@ -1009,6 +994,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) return ret; } + int iwl_pcie_tx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1045,14 +1031,15 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; } - } - if (trans->cfg->use_tfh) { - iwl_write_direct32(trans, TFH_TRANSFER_MODE, - TFH_TRANSFER_MAX_PENDING_REQ | - TFH_CHUNK_SIZE_128 | - TFH_CHUNK_SPLIT_MODE); - return 0; + /* + * Tell nic where to find circular buffer of TFDs for a + * given Tx queue, and enable the DMA channel used for that + * queue. + * Circular buffer (TFD queue in DRAM) physical base address + */ + iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), + trans_pcie->txq[txq_id].dma_addr >> 8); } iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); @@ -1068,6 +1055,51 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) return ret; } +int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + int txq_id, slots_num; + bool alloc = false; + + if (!trans_pcie->txq) { + /* TODO: change this when moving to new TX alloc model */ + ret = iwl_pcie_tx_alloc(trans); + if (ret) + goto error; + alloc = true; + } + + spin_lock(&trans_pcie->irq_lock); + + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); + + spin_unlock(&trans_pcie->irq_lock); + + /* TODO: remove this when moving to new TX alloc model */ + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) { + slots_num = (txq_id == trans_pcie->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_pcie_txq_init(trans, &trans_pcie->txq[txq_id], + slots_num, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return 0; + +error: + /* Upon error, free only if we allocated something */ + if (alloc) + iwl_pcie_tx_free(trans); + return ret; +} + static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) { lockdep_assert_held(&txq->lock); From 30d23c3cd035e92c8cc0f9f648a5acce105a2d5b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 30 Oct 2016 09:49:09 +0200 Subject: [PATCH 034/201] iwlwifi: mvm: remove call for paging in new init flow Now that transport inits the paging in the context info - remove the call in mvm. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 8 -------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 286f186097295..e481bb050c6e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -850,14 +850,6 @@ int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } - /* TODO: remove when integrating context info */ - ret = iwl_mvm_init_paging(mvm); - if (ret) { - IWL_ERR(mvm, "Failed to init paging: %d\n", - ret); - goto error; - } - /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { /* Read nvm */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b3f67fe982032..91bd5ebd5b653 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1709,7 +1709,8 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { - iwl_free_fw_paging(mvm); + if (!iwl_mvm_has_new_tx_api(mvm)) + iwl_free_fw_paging(mvm); mvm->ucode_loaded = false; iwl_trans_stop_device(mvm->trans); } From 87d0e1af9db3bff4ec2f68fd4d032f89c23867a4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 11 Jan 2017 21:33:38 +0200 Subject: [PATCH 035/201] iwlwifi: mvm: separate queue mapping from queue enablement As preparation for a000 different queue management, separate mapping of queues from actual enablement. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/utils.c | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index dedea96a8e0ff..8f199ff9be870 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright (C) 2015 Intel Deutschland GmbH + * Copyright (C) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -644,20 +645,19 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, return ret; } -void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, - unsigned int wdg_timeout) +static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, + int mac80211_queue, u8 sta_id, u8 tid) { bool enable_queue = true; spin_lock_bh(&mvm->queue_info_lock); /* Make sure this TID isn't already enabled */ - if (mvm->queue_info[queue].tid_bitmap & BIT(cfg->tid)) { + if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) { spin_unlock_bh(&mvm->queue_info_lock); IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n", - queue, cfg->tid); - return; + queue, tid); + return false; } /* Update mappings and refcounts */ @@ -666,17 +666,17 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, mvm->queue_info[queue].hw_queue_to_mac80211 |= BIT(mac80211_queue); mvm->queue_info[queue].hw_queue_refcount++; - mvm->queue_info[queue].tid_bitmap |= BIT(cfg->tid); - mvm->queue_info[queue].ra_sta_id = cfg->sta_id; + mvm->queue_info[queue].tid_bitmap |= BIT(tid); + mvm->queue_info[queue].ra_sta_id = sta_id; if (enable_queue) { - if (cfg->tid != IWL_MAX_TID_COUNT) + if (tid != IWL_MAX_TID_COUNT) mvm->queue_info[queue].mac80211_ac = - tid_to_mac80211_ac[cfg->tid]; + tid_to_mac80211_ac[tid]; else mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO; - mvm->queue_info[queue].txq_tid = cfg->tid; + mvm->queue_info[queue].txq_tid = tid; } IWL_DEBUG_TX_QUEUES(mvm, @@ -686,8 +686,16 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, spin_unlock_bh(&mvm->queue_info_lock); + return enable_queue; +} + +void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, + u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) +{ /* Send the enabling command if we need to */ - if (enable_queue) { + if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, + cfg->sta_id, cfg->tid)) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_ENABLE_QUEUE, From 169345d40d0fa05c4fdcec67835b008d24cfcf26 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 30 Mar 2017 15:57:23 -0700 Subject: [PATCH 036/201] ath6kl: add __printf verification to ath6kl_dbg Fix fallout too. Signed-off-by: Joe Perches Reviewed-by: Steve deRosier Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.h | 2 ++ drivers/net/wireless/ath/ath6kl/htc_pipe.c | 2 +- drivers/net/wireless/ath/ath6kl/wmi.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 0614393dd7ae7..94297572914fe 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -63,6 +63,7 @@ int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif); #ifdef CONFIG_ATH6KL_DEBUG +__printf(2, 3) void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...); void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, const char *msg, const char *prefix, @@ -83,6 +84,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar); void ath6kl_debug_cleanup(struct ath6kl *ar); #else +__printf(2, 3) static inline void ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, const char *fmt, ...) { diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index ca1a18c86c0d7..d127a08d60df6 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -995,7 +995,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, if (netlen < (payload_len + HTC_HDR_LENGTH)) { ath6kl_dbg(ATH6KL_DBG_HTC, - "HTC Rx: insufficient length, got:%d expected =%u\n", + "HTC Rx: insufficient length, got:%d expected =%zu\n", netlen, payload_len + HTC_HDR_LENGTH); status = -EINVAL; goto free_skb; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 84a6d12c3f8a3..a082de81ec4c2 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1596,7 +1596,7 @@ static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len, rate = le32_to_cpu(ev->rate); pkts = le32_to_cpu(ev->pkts); - ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n", + ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d%% pkts %d intvl %ds\n", vif->bssid, rate, pkts, vif->txe_intvl); cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts, From 62ca0690cd495bb7c1414cdf0cf790c2922a1d79 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Tue, 4 Apr 2017 22:22:56 +0530 Subject: [PATCH 037/201] ath10k: fix compile time sanity check for CE4 buffer size In 'ath10k_ce_alloc_pipe' the compile time sanity check to ensure that there is sufficient buffers in CE4 for HTT Tx MSDU descriptors, but this did not take into account of the case with 'peer flow control' enabled, fix this. Cc: Michal Kazior Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 9ac0a73a3a9f8..ee1090ca2eac5 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1051,7 +1051,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, */ BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(2 * TARGET_10X_NUM_MSDU_DESC > + BUILD_BUG_ON(2 * TARGET_10_4_NUM_MSDU_DESC_PFC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); From 82e9f646555442d63e47155171592ee790275ea3 Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Wed, 5 Apr 2017 14:58:04 +0300 Subject: [PATCH 038/201] wil6210: fix sequence for scan-abort during reset Communication with FW must be done before wil->status is initialized in order to properly handle cases where communication with FW halts during reset sequence. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c33cc4ad44c44..7e72096d738a9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -948,15 +948,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* Disable device led before reset*/ wmi_led_cfg(wil, false); + mutex_lock(&wil->p2p_wdev_mutex); + wil_abort_scan(wil, false); + mutex_unlock(&wil->p2p_wdev_mutex); + /* prevent NAPI from being scheduled and prevent wmi commands */ mutex_lock(&wil->wmi_mutex); bitmap_zero(wil->status, wil_status_last); mutex_unlock(&wil->wmi_mutex); - mutex_lock(&wil->p2p_wdev_mutex); - wil_abort_scan(wil, false); - mutex_unlock(&wil->p2p_wdev_mutex); - wil_mask_irq(wil); wmi_event_flush(wil); From 8b068c032a5cbe6f80168e0ecf2c9625c8d14d90 Mon Sep 17 00:00:00 2001 From: Lazar Alexei Date: Wed, 5 Apr 2017 14:58:05 +0300 Subject: [PATCH 039/201] wil6210: restore power save state after internal FW reset The power save profile is set to default state in case of FW reset, regardless of the state before the reset took place. Fix this by saving the current power save profile and restore it in case of FW reset. Signed-off-by: Lazar Alexei Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 12 +---------- drivers/net/wireless/ath/wil6210/main.c | 24 +++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 4 ++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 1981ec2e0186e..474ab8070c002 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1563,12 +1563,6 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_ps_profile_type ps_profile; - int rc; - - if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { - wil_err(wil, "set_power_mgmt not supported\n"); - return -EOPNOTSUPP; - } wil_dbg_misc(wil, "enabled=%d, timeout=%d\n", enabled, timeout); @@ -1578,11 +1572,7 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, else ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED; - rc = wmi_ps_dev_profile_cfg(wil, ps_profile); - if (rc) - wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); - - return rc; + return wil_ps_update(wil, ps_profile); } static const struct cfg80211_ops wil_cfg80211_ops = { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 7e72096d738a9..9aa81ce895b3e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -576,6 +576,9 @@ int wil_priv_init(struct wil6210_priv *wil) if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; + + wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + return 0; out_wmi_wq: @@ -903,6 +906,24 @@ void wil_abort_scan(struct wil6210_priv *wil, bool sync) } } +int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) +{ + int rc; + + if (!test_bit(WMI_FW_CAPABILITY_PS_CONFIG, wil->fw_capabilities)) { + wil_err(wil, "set_power_mgmt not supported\n"); + return -EOPNOTSUPP; + } + + rc = wmi_ps_dev_profile_cfg(wil, ps_profile); + if (rc) + wil_err(wil, "wmi_ps_dev_profile_cfg failed (%d)\n", rc); + else + wil->ps_profile = ps_profile; + + return rc; +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -1033,6 +1054,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) + wil_ps_update(wil, wil->ps_profile); + wil_collect_fw_info(wil); if (wil->platform_ops.notify) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fee18916b713b..9cedc2d642bab 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -691,6 +691,8 @@ struct wil6210_priv { /* High Access Latency Policy voting */ struct wil_halp halp; + enum wmi_ps_profile_type ps_profile; + #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP struct notifier_block pm_notify; @@ -812,6 +814,8 @@ 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_ps_update(struct wil6210_priv *wil, + enum wmi_ps_profile_type ps_profile); 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); From 52a457020a89158f4eb886544165dc162ca9a35e Mon Sep 17 00:00:00 2001 From: Lior David Date: Wed, 5 Apr 2017 14:58:06 +0300 Subject: [PATCH 040/201] wil6210: support 8KB RX buffers The 11ad spec requires 11ad devices to be able to receive 8KB packets over the air. Currently this is only possible by loading the driver with mtu_max=7912 but this also forces a smaller block ACK window size which reduces performance for stations which transmit normal sized packets (<2KB). Fix this problem as follows: 1. Add a module parameter rx_large_buf that when set, will allocate 8KB RX buffers regardless of mtu_max setting. 2. When receiving block ACK request agree to any window size not above our maximum, regardless of the mtu_max setting. This means if the other side transmits small packets (2KB) it can still set up block ACK with a large window size, and get better performance. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/rx_reorder.c | 12 ++++++++-- drivers/net/wireless/ath/wil6210/txrx.c | 24 +++++++++++++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ drivers/net/wireless/ath/wil6210/wmi.c | 3 ++- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 7404b6f39c6af..a43cffcf1bbf7 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -343,8 +343,16 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); status = WLAN_STATUS_INVALID_QOS_PARAM; } - if (status == WLAN_STATUS_SUCCESS) - agg_wsize = wil_agg_size(wil, req_agg_wsize); + if (status == WLAN_STATUS_SUCCESS) { + if (req_agg_wsize == 0) { + wil_dbg_misc(wil, "Suggest BACK wsize %d\n", + WIL_MAX_AGG_WSIZE); + agg_wsize = WIL_MAX_AGG_WSIZE; + } else { + agg_wsize = min_t(u16, + WIL_MAX_AGG_WSIZE, req_agg_wsize); + } + } rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, agg_amsdu, agg_wsize, agg_timeout); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 67f50ae17cd3f..edab4c0a900ff 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -37,6 +37,10 @@ bool rx_align_2; module_param(rx_align_2, bool, 0444); MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no"); +bool rx_large_buf; +module_param(rx_large_buf, bool, 0444); +MODULE_PARM_DESC(rx_large_buf, " allocate 8KB RX buffers, default - no"); + static inline uint wil_rx_snaplen(void) { return rx_align_2 ? 6 : 0; @@ -255,7 +259,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, u32 i, int headroom) { struct device *dev = wil_to_dev(wil); - unsigned int sz = mtu_max + ETH_HLEN + wil_rx_snaplen(); + unsigned int sz = wil->rx_buf_len + ETH_HLEN + wil_rx_snaplen(); struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; @@ -419,7 +423,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct sk_buff *skb; dma_addr_t pa; unsigned int snaplen = wil_rx_snaplen(); - unsigned int sz = mtu_max + ETH_HLEN + snaplen; + unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen; u16 dmalen; u8 ftype; int cid; @@ -780,6 +784,20 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) wil_rx_refill(wil, v->size); } +static void wil_rx_buf_len_init(struct wil6210_priv *wil) +{ + wil->rx_buf_len = rx_large_buf ? + WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; + if (mtu_max > wil->rx_buf_len) { + /* do not allow RX buffers to be smaller than mtu_max, for + * backward compatibility (mtu_max parameter was also used + * to support receiving large packets) + */ + wil_info(wil, "Override RX buffer to mtu_max(%d)\n", mtu_max); + wil->rx_buf_len = mtu_max; + } +} + int wil_rx_init(struct wil6210_priv *wil, u16 size) { struct vring *vring = &wil->vring_rx; @@ -792,6 +810,8 @@ int wil_rx_init(struct wil6210_priv *wil, u16 size) return -EINVAL; } + wil_rx_buf_len_init(wil); + vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9cedc2d642bab..2af4a643bd031 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -32,6 +32,7 @@ extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; extern u32 vring_idle_trsh; extern bool rx_align_2; +extern bool rx_large_buf; extern bool debug_fw; extern bool disable_ap_sme; @@ -656,6 +657,7 @@ struct wil6210_priv { struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; + unsigned int rx_buf_len; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 9255c47af15a8..e6c249d47487b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1398,7 +1398,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .max_mpdu_size = cpu_to_le16( + wil_mtu2macbuf(wil->rx_buf_len)), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, From 90ffabb08b7d0627239c7dd53c3c7065a158508c Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 5 Apr 2017 14:58:07 +0300 Subject: [PATCH 041/201] wil6210: align to latest auto generated wmi.h Align to latest version of the auto generated wmi file describing the interface with FW Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.h | 73 ++++++++++++++++++-------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 7c9fee57aa911..f7f5f4f801e38 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -58,6 +58,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, WMI_FW_CAPABILITY_WMI_ONLY = 5, + WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, WMI_FW_CAPABILITY_MAX, }; @@ -142,8 +143,6 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x851, WMI_RS_MGMT_CMDID = 0x852, WMI_RF_MGMT_CMDID = 0x853, - WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x854, - WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x855, WMI_OTP_READ_CMDID = 0x856, WMI_OTP_WRITE_CMDID = 0x857, WMI_LED_CFG_CMDID = 0x858, @@ -192,6 +191,8 @@ enum wmi_command_id { WMI_GET_MGMT_RETRY_LIMIT_CMDID = 0x931, WMI_NEW_STA_CMDID = 0x935, WMI_DEL_STA_CMDID = 0x936, + WMI_SET_THERMAL_THROTTLING_CFG_CMDID = 0x940, + WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941, WMI_TOF_SESSION_START_CMDID = 0x991, WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, WMI_TOF_SET_LCR_CMDID = 0x993, @@ -438,16 +439,6 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; -/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ -#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) - -/* WMI_THERMAL_THROTTLING_CTRL_CMDID */ -struct wmi_thermal_throttling_ctrl_cmd { - __le32 time_on_usec; - __le32 time_off_usec; - __le32 max_txop_length_usec; -} __packed; - /* WMI_RF_RX_TEST_CMDID */ struct wmi_rf_rx_test_cmd { __le32 sector; @@ -549,7 +540,7 @@ struct wmi_pcp_start_cmd { u8 hidden_ssid; u8 is_go; u8 reserved0[5]; - /* abft_len override if non-0 */ + /* A-BFT length override if non-0 */ u8 abft_len; u8 disable_ap_sme; u8 network_type; @@ -910,6 +901,39 @@ struct wmi_set_mgmt_retry_limit_cmd { u8 reserved[3]; } __packed; +/* Zones: HIGH, MAX, CRITICAL */ +#define WMI_NUM_OF_TT_ZONES (3) + +struct wmi_tt_zone_limits { + /* Above this temperature this zone is active */ + u8 temperature_high; + /* Below this temperature the adjacent lower zone is active */ + u8 temperature_low; + u8 reserved[2]; +} __packed; + +/* Struct used for both configuration and status commands of thermal + * throttling + */ +struct wmi_tt_data { + /* Enable/Disable TT algorithm for baseband */ + u8 bb_enabled; + u8 reserved0[3]; + /* Define zones for baseband */ + struct wmi_tt_zone_limits bb_zones[WMI_NUM_OF_TT_ZONES]; + /* Enable/Disable TT algorithm for radio */ + u8 rf_enabled; + u8 reserved1[3]; + /* Define zones for all radio chips */ + struct wmi_tt_zone_limits rf_zones[WMI_NUM_OF_TT_ZONES]; +} __packed; + +/* WMI_SET_THERMAL_THROTTLING_CFG_CMDID */ +struct wmi_set_thermal_throttling_cfg_cmd { + /* Command data */ + struct wmi_tt_data tt_data; +} __packed; + /* WMI_NEW_STA_CMDID */ struct wmi_new_sta_cmd { u8 dst_mac[WMI_MAC_LEN]; @@ -1040,7 +1064,6 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, - WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -1090,6 +1113,8 @@ enum wmi_event_id { WMI_BRP_SET_ANT_LIMIT_EVENTID = 0x1924, WMI_SET_MGMT_RETRY_LIMIT_EVENTID = 0x1930, WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931, + WMI_SET_THERMAL_THROTTLING_CFG_EVENTID = 0x1940, + WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941, WMI_TOF_SESSION_END_EVENTID = 0x1991, WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, WMI_TOF_SET_LCR_EVENTID = 0x1993, @@ -1133,13 +1158,6 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; -/* WMI_THERMAL_THROTTLING_STATUS_EVENTID */ -struct wmi_thermal_throttling_status_event { - __le32 time_on_usec; - __le32 time_off_usec; - __le32 max_txop_length_usec; -} __packed; - /* WMI_GET_STATUS_DONE_EVENTID */ struct wmi_get_status_done_event { __le32 is_associated; @@ -2206,6 +2224,19 @@ struct wmi_tof_get_capabilities_event { __le32 aoa_supported_types; } __packed; +/* WMI_SET_THERMAL_THROTTLING_CFG_EVENTID */ +struct wmi_set_thermal_throttling_cfg_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_GET_THERMAL_THROTTLING_CFG_EVENTID */ +struct wmi_get_thermal_throttling_cfg_event { + /* Status data */ + struct wmi_tt_data tt_data; +} __packed; + enum wmi_tof_session_end_status { WMI_TOF_SESSION_END_NO_ERROR = 0x00, WMI_TOF_SESSION_END_FAIL = 0x01, From b819447dfc4bd120c9d6cd8521252d544fce8fe7 Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Wed, 5 Apr 2017 14:58:08 +0300 Subject: [PATCH 042/201] wil6210: fix protection against connections during reset Existing code that ignores connection events during reset flow will never take effect since it locks the same mutex taken by the reset flow. In addition, in case of unsolicited disconnect events ignore those as well since device is about to get reset. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index e6c249d47487b..814c35645b737 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -518,16 +518,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) assoc_resp_ielen = 0; } - mutex_lock(&wil->mutex); if (test_bit(wil_status_resetting, wil->status) || !test_bit(wil_status_fwready, wil->status)) { wil_err(wil, "status_resetting, cancel connect event, CID %d\n", evt->cid); - mutex_unlock(&wil->mutex); /* no need for cleanup, wil_reset will do that */ return; } + mutex_lock(&wil->mutex); + if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (!test_bit(wil_status_fwconnecting, wil->status)) { @@ -631,6 +631,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; + if (test_bit(wil_status_resetting, wil->status) || + !test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "status_resetting, cancel disconnect event\n"); + /* no need for cleanup, wil_reset will do that */ + return; + } + mutex_lock(&wil->mutex); wil6210_disconnect(wil, evt->bssid, reason_code, true); mutex_unlock(&wil->mutex); From a3839fbcf0351e8192429f1cc1c499799465737f Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Wed, 5 Apr 2017 14:58:09 +0300 Subject: [PATCH 043/201] wil6210: protect against sporadic interrupt during suspend flow During the suspend flow, wil6210 HW can send sporadic interrupts, while PCIe bus is not operational. To prevent that, keep the interrupts disabled during the suspend flow and re-enable them only after PCIe enablement in resume. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index a0acb2d0cb793..7260bef314a44 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -80,12 +80,20 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) } } - if (wil->platform_ops.suspend) + /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */ + wil_dbg_pm(wil, "Disabling PCIe IRQ before suspending\n"); + wil_disable_irq(wil); + + if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); + if (rc) + wil_enable_irq(wil); + } out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); + return rc; } @@ -104,6 +112,9 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) } } + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method * invocation. This prevent recursive call to wil_up() From 4d4f8132f72b78d1260ec9afa94c3b44deb12adf Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Wed, 5 Apr 2017 14:58:10 +0300 Subject: [PATCH 044/201] wil6210: fix check for sparrow D0 FW file Driver fails to load FW for sparrow D0 devices in some cases. Fix this by returning correct value from wil_fw_verify_file_exists when D0 FW file is not detected for any reason. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/fw_inc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index f4901587c0057..e01acac88825d 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -554,5 +554,7 @@ bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name) rc = request_firmware(&fw, name, wil_to_dev(wil)); if (!rc) release_firmware(fw); - return rc != -ENOENT; + else + wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc); + return !rc; } From 0f6edfe2bbbb59d161580cb4870fcc46f5490f85 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 5 Apr 2017 14:58:11 +0300 Subject: [PATCH 045/201] wil6210: fix memory access violation in wil_memcpy_from/toio_32 In case count is not multiple of 4, there is a read access in wil_memcpy_toio_32() from outside src buffer boundary. In wil_memcpy_fromio_32(), in case count is not multiple of 4, there is a write access to outside dst io memory boundary. Fix these issues with proper handling of the last 1 to 4 copied bytes. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 9aa81ce895b3e..439d27c3aeae0 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -130,9 +130,15 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, u32 *d = dst; const volatile u32 __iomem *s = src; - /* size_t is unsigned, if (count%4 != 0) it will wrap */ - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) *d++ = __raw_readl(s++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = __raw_readl(s); + + memcpy(d, &tmp, count); + } } void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, @@ -149,8 +155,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, volatile u32 __iomem *d = dst; const u32 *s = src; - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) __raw_writel(*s++, d++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = 0; + + memcpy(&tmp, s, count); + __raw_writel(tmp, d); + } } void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, From bd50e2688a7812754e964231c850e8414751df1d Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Wed, 5 Apr 2017 14:58:12 +0300 Subject: [PATCH 046/201] wil6210: remove HALP voting in debugfs ioblob debugfs ioblob function is called by the FW logs scripts to copy the FW logs via PCIe. As the FW logs collection is done in parallel to the operational 11AD actions, the HALP voting can take place during 11AD reset flow and other sensitive scenarios. To prevent that, remove HALP voting from the ioblob function. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 5 ++--- drivers/net/wireless/ath/wil6210/main.c | 17 ----------------- drivers/net/wireless/ath/wil6210/wil6210.h | 6 ------ 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 3e8cdf12fedad..5648ebbd0e166 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -524,9 +524,8 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - wil_memcpy_fromio_halp_vote(wil_blob->wil, buf, - (const volatile void __iomem *) - wil_blob->blob.data + pos, count); + wil_memcpy_fromio_32(buf, (const void __iomem *) + wil_blob->blob.data + pos, count); ret = copy_to_user(user_buf, buf, count); kfree(buf); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 439d27c3aeae0..32086792dfc30 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -141,14 +141,6 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, } } -void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, - const volatile void __iomem *src, size_t count) -{ - wil_halp_vote(wil); - wil_memcpy_fromio_32(dst, src, count); - wil_halp_unvote(wil); -} - void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count) { @@ -167,15 +159,6 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, } } -void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, - volatile void __iomem *dst, - const void *src, size_t count) -{ - wil_halp_vote(wil); - wil_memcpy_toio_32(dst, src, count); - wil_halp_unvote(wil); -} - static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, u16 reason_code, bool from_event) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 2af4a643bd031..ec646d7df522f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -803,12 +803,6 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count); -void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, - const volatile void __iomem *src, - size_t count); -void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, - volatile void __iomem *dst, - const void *src, size_t count); void *wil_if_alloc(struct device *dev); void wil_if_free(struct wil6210_priv *wil); From 98a830a98dab6d474190bec72c4a4ad0f7f9bf75 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 5 Apr 2017 14:58:13 +0300 Subject: [PATCH 047/201] wil6210: fix array out of bounds access in pmc Array index 'i' is used before limits check. Fix this by doing limits check first. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index b067fdf086d41..2e301b6b32a9c 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -200,7 +200,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, release_pmc_skbs: wil_err(wil, "exit on error: Releasing skbs...\n"); - for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) { + for (i = 0; i < num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, descriptor_size, pmc->descriptors[i].va, @@ -283,7 +283,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) int i; for (i = 0; - pmc->descriptors[i].va && i < pmc->num_descriptors; i++) { + i < pmc->num_descriptors && pmc->descriptors[i].va; i++) { dma_free_coherent(dev, pmc->descriptor_size, pmc->descriptors[i].va, From 3161adddf309e4c5f362d77f92206dd340fea67d Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Wed, 5 Apr 2017 14:58:14 +0300 Subject: [PATCH 048/201] wil6210: prevent access to 11AD device if resume fails In case wil6210 resume fails, wil6210 suspend function will try to access the suspended device in the next kernel suspend. To prevent that, add wil_status_suspended flag to indicate if the device is already suspended and clear it only if the resume succeeds. Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/pm.c | 16 ++++++++++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 7260bef314a44..2ae4fe85cc8cd 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -71,6 +71,11 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 0; + } + /* if netif up, hardware is alive, shut it down */ if (ndev->flags & IFF_UP) { rc = wil_down(wil); @@ -86,10 +91,14 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); - if (rc) + if (rc) { wil_enable_irq(wil); + goto out; + } } + set_bit(wil_status_suspended, wil->status); + out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); @@ -117,10 +126,13 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method - * invocation. This prevent recursive call to wil_up() + * invocation. This prevent recursive call to wil_up(). + * wil_status_suspended will be cleared in wil_reset */ if (ndev->flags & IFF_UP) rc = wil_up(wil); + else + clear_bit(wil_status_suspended, wil->status); out: wil_dbg_pm(wil, "resume: %s => %d\n", diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ec646d7df522f..b00c803a1e83c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -412,6 +412,7 @@ enum { /* for wil6210_priv.status */ wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ wil_status_resetting, /* reset in progress */ + wil_status_suspended, /* suspend completed, device is suspended */ wil_status_last /* keep last */ }; From ecd7eb7c2bcf99f6c23d68ad56ce15949da848a1 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Tue, 4 Apr 2017 10:16:28 +0530 Subject: [PATCH 049/201] mwifiex: Fix invalid port issue We have to use start port, for TX/RX of single packet, instead of current aggregating port. This will fix SDIO CMD53(TX/RX) returning -ETIMEDOUT and halting the data path. Fixes: 0cb52aac4d19 ("mwifiex: do not set multiport flag for tx/rx single packet") Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 424532b81c2de..0af1c6733c925 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1380,7 +1380,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_rx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_rx.start_port; if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, mport, 1)) @@ -1813,7 +1813,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_tx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_tx.start_port; ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, card->mpa_tx.buf_len, mport); From 6e84ab604bdedaa16239bd1c6e5fcb5660309f02 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 5 Apr 2017 20:33:26 +0200 Subject: [PATCH 050/201] brcmfmac: properly align buffers on certain platforms with 64 bit DMA Systems with 64 bit DMA at least partially require buffers to be used for DMA to be 8-byte-aligned. One example is Amlogic Meson GX. Switching the MMC/SDIO driver for this platform to SG DMA mode resulted in problems due to unaligned buffers. Fortunately the brcmfmac driver has a global define for the alignment. Changing it to 8 fixed the issues with Meson GX. Suggested-by: Helmut Klein Tested-by: Helmut Klein Signed-off-by: Heiner Kallweit Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index a999f95062c7d..fc64b8913aa6a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -540,7 +540,11 @@ static int qcount[NUMPRIO]; /* Limit on rounding up frames */ static const uint max_roundup = 512; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +#define ALIGNMENT 8 +#else #define ALIGNMENT 4 +#endif enum brcmf_sdio_frmtype { BRCMF_SDIO_FT_NORMAL, From ffb9f18ad8f0e5e1d88c56478bf24e6464c96eee Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:37 +0100 Subject: [PATCH 051/201] brcmfmac: rename brcmf_fws_{de,}init to brcmf_fws{at,de}tach This is a non-functional change to align the fwsignal module to the naming pattern used throughout the driver. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 4 ++-- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 6 +++--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 24da6276d29d9..9628084b7aa03 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -420,7 +420,7 @@ brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp) static int brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) { - return brcmf_fws_init(drvr); + return brcmf_fws_attach(drvr); } int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) @@ -464,7 +464,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) { - brcmf_fws_deinit(drvr); + brcmf_fws_detach(drvr); kfree(drvr->proto->pd); drvr->proto->pd = NULL; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 5f1a5929cb307..c27a2254f416a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2308,7 +2308,7 @@ static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) } #endif -int brcmf_fws_init(struct brcmf_pub *drvr) +int brcmf_fws_attach(struct brcmf_pub *drvr) { struct brcmf_fws_info *fws; struct brcmf_if *ifp; @@ -2408,11 +2408,11 @@ int brcmf_fws_init(struct brcmf_pub *drvr) return 0; fail: - brcmf_fws_deinit(drvr); + brcmf_fws_detach(drvr); return rc; } -void brcmf_fws_deinit(struct brcmf_pub *drvr) +void brcmf_fws_detach(struct brcmf_pub *drvr) { struct brcmf_fws_info *fws = drvr->fws; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index 96df66073b2a1..d72515867aa0d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -18,8 +18,8 @@ #ifndef FWSIGNAL_H_ #define FWSIGNAL_H_ -int brcmf_fws_init(struct brcmf_pub *drvr); -void brcmf_fws_deinit(struct brcmf_pub *drvr); +int brcmf_fws_attach(struct brcmf_pub *drvr); +void brcmf_fws_detach(struct brcmf_pub *drvr); bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws); bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); From fc0471e3e884a13d293afae53917ef8ff33b8ae5 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:38 +0100 Subject: [PATCH 052/201] brcmfmac: ignore interfaces when fwsignal is disabled When brcmf_fws_add_interface() is called the struct brcmf_if::fws_desc field is initialized regardless the state of the fwsignal functionality, ie. the fcmode. This is not needed when fcmode is NONE, which is the default mode. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index c27a2254f416a..23b2b3fa1c2c9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2145,7 +2145,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) struct brcmf_fws_info *fws = ifp->drvr->fws; struct brcmf_fws_mac_descriptor *entry; - if (!ifp->ndev) + if (!ifp->ndev || fws->fcmode == BRCMF_FWS_FCMODE_NONE) return; entry = &fws->desc.iface[ifp->ifidx]; From acf8ac41dd733508b9e77483f96e53610c87fa64 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:39 +0100 Subject: [PATCH 053/201] brcmfmac: remove reference to fwsignal data from struct brcmf_pub The fwsignal module is part of the bcdc protocol and as such does its instance data is not needed in core structure. Moving it into struct brcmf_bcdc instead. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/bcdc.c | 35 ++++++++++--- .../broadcom/brcm80211/brcmfmac/bcdc.h | 1 + .../broadcom/brcm80211/brcmfmac/core.h | 2 - .../broadcom/brcm80211/brcmfmac/fwsignal.c | 51 +++++++++---------- .../broadcom/brcm80211/brcmfmac/fwsignal.h | 4 +- 5 files changed, 54 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 9628084b7aa03..9f2d0b0cf6e5c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -103,9 +103,17 @@ struct brcmf_bcdc { u8 bus_header[BUS_HEADER_LEN]; struct brcmf_proto_bcdc_dcmd msg; unsigned char buf[BRCMF_DCMD_MAXLEN]; + struct brcmf_fws_info *fws; }; +struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr) +{ + struct brcmf_bcdc *bcdc = drvr->proto->pd; + + return bcdc->fws; +} + static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len, bool set) @@ -330,8 +338,9 @@ static int brcmf_proto_bcdc_tx_queue_data(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb) { struct brcmf_if *ifp = brcmf_get_ifp(drvr, ifidx); + struct brcmf_bcdc *bcdc = drvr->proto->pd; - if (!brcmf_fws_queue_skbs(drvr->fws)) + if (!brcmf_fws_queue_skbs(bcdc->fws)) return brcmf_proto_txdata(drvr, ifidx, 0, skb); return brcmf_fws_process_skb(ifp, skb); @@ -360,15 +369,15 @@ brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp, bool success) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_bcdc *bcdc = bus_if->drvr->proto->pd; struct brcmf_if *ifp; /* await txstatus signal for firmware if active */ - if (brcmf_fws_fc_active(drvr->fws)) { + if (brcmf_fws_fc_active(bcdc->fws)) { if (!success) - brcmf_fws_bustxfail(drvr->fws, txp); + brcmf_fws_bustxfail(bcdc->fws, txp); } else { - if (brcmf_proto_bcdc_hdrpull(drvr, false, txp, &ifp)) + if (brcmf_proto_bcdc_hdrpull(bus_if->drvr, false, txp, &ifp)) brcmu_pkt_buf_free_skb(txp); else brcmf_txfinalize(ifp, txp, success); @@ -420,7 +429,15 @@ brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp) static int brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) { - return brcmf_fws_attach(drvr); + struct brcmf_bcdc *bcdc = drvr->proto->pd; + struct brcmf_fws_info *fws; + + fws = brcmf_fws_attach(drvr); + if (IS_ERR(fws)) + return PTR_ERR(fws); + + bcdc->fws = fws; + return 0; } int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) @@ -464,7 +481,9 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) { - brcmf_fws_detach(drvr); - kfree(drvr->proto->pd); + struct brcmf_bcdc *bcdc = drvr->proto->pd; + drvr->proto->pd = NULL; + brcmf_fws_detach(bcdc->fws); + kfree(bcdc); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h index b6fa7a836cdae..3b0e9eff21b58 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.h @@ -22,6 +22,7 @@ void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr); void brcmf_proto_bcdc_txflowblock(struct device *dev, bool state); void brcmf_proto_bcdc_txcomplete(struct device *dev, struct sk_buff *txp, bool success); +struct brcmf_fws_info *drvr_to_fws(struct brcmf_pub *drvr); #else static inline int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { return 0; } static inline void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) {} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 6aecd8dfd824d..a4dd313140f37 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -127,8 +127,6 @@ struct brcmf_pub { struct brcmf_fweh_info fweh; - struct brcmf_fws_info *fws; - struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 23b2b3fa1c2c9..72373e59308e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -36,6 +36,7 @@ #include "p2p.h" #include "cfg80211.h" #include "proto.h" +#include "bcdc.h" #include "common.h" /** @@ -1586,7 +1587,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_fws_info *fws = ifp->drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); int i; u8 *credits = data; @@ -1617,7 +1618,7 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp, const struct brcmf_event_msg *e, void *data) { - struct brcmf_fws_info *fws = ifp->drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); if (fws) { brcmf_fws_lock(fws); @@ -1826,7 +1827,7 @@ void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt) void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) { struct brcmf_skb_reorder_data *rd; - struct brcmf_fws_info *fws = ifp->drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); u8 *signal_data; s16 data_len; u8 type; @@ -2091,8 +2092,7 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p, int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) { - struct brcmf_pub *drvr = ifp->drvr; - struct brcmf_fws_info *fws = drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); struct ethhdr *eh = (struct ethhdr *)(skb->data); int fifo = BRCMF_FWS_FIFO_BCMC; @@ -2142,7 +2142,7 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp) void brcmf_fws_add_interface(struct brcmf_if *ifp) { - struct brcmf_fws_info *fws = ifp->drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); struct brcmf_fws_mac_descriptor *entry; if (!ifp->ndev || fws->fcmode == BRCMF_FWS_FCMODE_NONE) @@ -2160,16 +2160,17 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) void brcmf_fws_del_interface(struct brcmf_if *ifp) { struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); if (!entry) return; - brcmf_fws_lock(ifp->drvr->fws); + brcmf_fws_lock(fws); ifp->fws_desc = NULL; brcmf_dbg(TRACE, "deleting %s\n", entry->name); brcmf_fws_macdesc_deinit(entry); - brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); - brcmf_fws_unlock(ifp->drvr->fws); + brcmf_fws_cleanup(fws, ifp->ifidx); + brcmf_fws_unlock(fws); } static void brcmf_fws_dequeue_worker(struct work_struct *worker) @@ -2243,7 +2244,7 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) { struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); - struct brcmf_fws_stats *fwstats = &bus_if->drvr->fws->stats; + struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats); seq_printf(seq, "header_pulls: %u\n" @@ -2308,7 +2309,7 @@ static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) } #endif -int brcmf_fws_attach(struct brcmf_pub *drvr) +struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr) { struct brcmf_fws_info *fws; struct brcmf_if *ifp; @@ -2316,17 +2317,15 @@ int brcmf_fws_attach(struct brcmf_pub *drvr) int rc; u32 mode; - drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); - if (!drvr->fws) { + fws = kzalloc(sizeof(*fws), GFP_KERNEL); + if (!fws) { rc = -ENOMEM; goto fail; } - fws = drvr->fws; - spin_lock_init(&fws->spinlock); - /* set linkage back */ + /* store drvr reference */ fws->drvr = drvr; fws->fcmode = drvr->settings->fcmode; @@ -2334,7 +2333,7 @@ int brcmf_fws_attach(struct brcmf_pub *drvr) (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) { fws->avoid_queueing = true; brcmf_dbg(INFO, "FWS queueing will be avoided\n"); - return 0; + return fws; } fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); @@ -2396,6 +2395,7 @@ int brcmf_fws_attach(struct brcmf_pub *drvr) brcmf_fws_hanger_init(&fws->hanger); brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0); brcmf_fws_macdesc_set_name(fws, &fws->desc.other); + brcmf_dbg(INFO, "added %s\n", fws->desc.other.name); brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, BRCMF_FWS_PSQ_LEN); @@ -2405,27 +2405,24 @@ int brcmf_fws_attach(struct brcmf_pub *drvr) brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", fws->fw_signals ? "enabled" : "disabled", tlv); - return 0; + return fws; fail: - brcmf_fws_detach(drvr); - return rc; + brcmf_fws_detach(fws); + return ERR_PTR(rc); } -void brcmf_fws_detach(struct brcmf_pub *drvr) +void brcmf_fws_detach(struct brcmf_fws_info *fws) { - struct brcmf_fws_info *fws = drvr->fws; - if (!fws) return; - if (drvr->fws->fws_wq) - destroy_workqueue(drvr->fws->fws_wq); + if (fws->fws_wq) + destroy_workqueue(fws->fws_wq); /* cleanup */ brcmf_fws_lock(fws); brcmf_fws_cleanup(fws, -1); - drvr->fws = NULL; brcmf_fws_unlock(fws); /* free top structure */ @@ -2461,7 +2458,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) { - struct brcmf_fws_info *fws = drvr->fws; + struct brcmf_fws_info *fws = drvr_to_fws(drvr); struct brcmf_if *ifp; int i; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index d72515867aa0d..ba07bd9720020 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -18,8 +18,8 @@ #ifndef FWSIGNAL_H_ #define FWSIGNAL_H_ -int brcmf_fws_attach(struct brcmf_pub *drvr); -void brcmf_fws_detach(struct brcmf_pub *drvr); +struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); +void brcmf_fws_detach(struct brcmf_fws_info *fws); bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws); bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); From 4835f37e3bafc138f8bfa3cbed2920dd56fed283 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:40 +0100 Subject: [PATCH 054/201] brcmfmac: add length checks in scheduled scan result handler Assure the event data buffer is long enough to hold the array of netinfo items and that SSID length does not exceed the maximum of 32 characters as per 802.11 spec. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 89ac12437c928..760781f4abd24 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3300,6 +3300,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, struct brcmf_pno_scanresults_le *pfn_result; u32 result_count; u32 status; + u32 datalen; brcmf_dbg(SCAN, "Enter\n"); @@ -3326,6 +3327,14 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, brcmf_err("FALSE PNO Event. (pfn_count == 0)\n"); goto out_err; } + + netinfo_start = brcmf_get_netinfo_array(pfn_result); + datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result); + if (datalen < result_count * sizeof(*netinfo)) { + brcmf_err("insufficient event data\n"); + goto out_err; + } + request = brcmf_alloc_internal_escan_request(wiphy, result_count); if (!request) { @@ -3333,8 +3342,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } - netinfo_start = brcmf_get_netinfo_array(pfn_result); - for (i = 0; i < result_count; i++) { netinfo = &netinfo_start[i]; if (!netinfo) { @@ -3344,6 +3351,8 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, goto out_err; } + if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN) + netinfo->SSID_len = IEEE80211_MAX_SSID_LEN; brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n", netinfo->SSID, netinfo->channel); err = brcmf_internal_escan_add_info(request, From 6594e1e8343645fe849a2ad42fcab94e2cf5b2c0 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:41 +0100 Subject: [PATCH 055/201] brcmfmac: remove bogus check in scheduled scan result handler Checking whether the address of an array element is null is bogus so removing it. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 760781f4abd24..b687533e5c280 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3344,12 +3344,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, for (i = 0; i < result_count; i++) { netinfo = &netinfo_start[i]; - if (!netinfo) { - brcmf_err("Invalid netinfo ptr. index: %d\n", - i); - err = -EINVAL; - goto out_err; - } if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN) netinfo->SSID_len = IEEE80211_MAX_SSID_LEN; From 6ea51fc708aedcf411f355de65a704ecda501bc4 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Thu, 6 Apr 2017 13:14:42 +0100 Subject: [PATCH 056/201] brcmfmac: only add channels and ssids once in scan request When receiving pno results there may be duplicate channels and/or ssids. Assure each is added only once when preparing the internal escan request. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b687533e5c280..0a067e59f90b5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3216,7 +3216,7 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, { struct ieee80211_channel *chan; enum nl80211_band band; - int freq; + int freq, i; if (channel <= CH_MAX_2G_CHANNEL) band = NL80211_BAND_2GHZ; @@ -3231,10 +3231,22 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req, if (!chan) return -EINVAL; - req->channels[req->n_channels++] = chan; - memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len); - req->ssids[req->n_ssids++].ssid_len = ssid_len; + for (i = 0; i < req->n_channels; i++) { + if (req->channels[i] == chan) + break; + } + if (i == req->n_channels) + req->channels[req->n_channels++] = chan; + for (i = 0; i < req->n_ssids; i++) { + if (req->ssids[i].ssid_len == ssid_len && + !memcmp(req->ssids[i].ssid, ssid, ssid_len)) + break; + } + if (i == req->n_ssids) { + memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len); + req->ssids[req->n_ssids++].ssid_len = ssid_len; + } return 0; } From b01127b268339fe12d3e1cbda4ceef1e89e0a086 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:54 -0500 Subject: [PATCH 057/201] rtlwifi: btcoex: 23b 2ant: check PS state before setting tdma duration For time division multiple access, the wifi and bt take turns to transmit, but we need to let AP know that wifi is under standby mode by sending null data to "pretend" entering power saving state using lps rpwm. But, the fw does not know if it is the actual power saving mode or just a fake one to cheat to the AP. Hence, before fw setting the tdma duration, the fw needs the driver to check the power saving state first. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 95 +++++++++++++++++++ .../rtlwifi/btcoexist/halbtc8723b2ant.h | 6 ++ 2 files changed, 101 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 988f276531dde..dda14bd0ac45a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -978,6 +978,33 @@ static void btc8723b2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); } +static void btc8723b2ant_set_lps_rpwm(struct btc_coexist *btcoexist, + u8 lps_val, u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void btc8723b2ant_lps_rpwm(struct btc_coexist *btcoexist, + bool force_exec, u8 lps_val, u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + btc8723b2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + static void btc8723b2ant_ignore_wlan_act(struct btc_coexist *btcoexist, bool force_exec, bool enable) { @@ -1341,9 +1368,74 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } +static void btc8723b2ant_ps_tdma_check_for_power_save_state( + struct btc_coexist *btcoexist, bool new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { + /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + } else { + /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +static void btc8723b2ant_power_save_state(struct btc_coexist *btcoexist, + u8 ps_type, u8 lps_val, u8 rpwm_val) +{ + bool low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + btc8723b2ant_ps_tdma_check_for_power_save_state(btcoexist, + true); + btc8723b2ant_lps_rpwm(btcoexist, NORMAL_EXEC, lps_val, + rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + btc8723b2ant_ps_tdma_check_for_power_save_state(btcoexist, + false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) { /* fw all off */ + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); @@ -1359,6 +1451,7 @@ static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) { /* force to reset coex mechanism*/ + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); btc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); @@ -1801,6 +1894,8 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) /* for HID quality & wifi performance balance at 11n mode */ btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 746930d0d2441..5bcaeceada9c3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -122,6 +122,11 @@ struct coex_dm_8723b_2ant { u8 bt_status; u8 wifi_chnl_info[3]; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + bool need_recover_0x948; u16 backup_0x948; }; @@ -160,6 +165,7 @@ struct coex_sta_8723b_2ant { u32 crc_err_11g; u32 crc_err_11n; u32 crc_err_11n_agg; + bool force_lps_on; u8 a2dp_bit_pool; }; From b91ed731393bc3fe9da3a0d909d6a3fdf7685232 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:55 -0500 Subject: [PATCH 058/201] rtlwifi: btcoex: 23b 2ant: rename tdma_adj_type to ps_tdma_du_adj_type The variable is for PS tdma duration adjust, so rename it to clearly to specify its usage. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 30 +++++++++---------- .../rtlwifi/btcoexist/halbtc8723b2ant.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index dda14bd0ac45a..30b2b93e92cac 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1632,34 +1632,34 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); - coex_dm->tdma_adj_type = 13; + coex_dm->ps_tdma_du_adj_type = 13; } else if (max_interval == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); - coex_dm->tdma_adj_type = 14; + coex_dm->ps_tdma_du_adj_type = 14; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); - coex_dm->tdma_adj_type = 15; + coex_dm->ps_tdma_du_adj_type = 15; } } else { if (max_interval == 1) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); - coex_dm->tdma_adj_type = 9; + coex_dm->ps_tdma_du_adj_type = 9; } else if (max_interval == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); - coex_dm->tdma_adj_type = 10; + coex_dm->ps_tdma_du_adj_type = 10; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); - coex_dm->tdma_adj_type = 11; + coex_dm->ps_tdma_du_adj_type = 11; } } } else { @@ -1668,34 +1668,34 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); - coex_dm->tdma_adj_type = 5; + coex_dm->ps_tdma_du_adj_type = 5; } else if (max_interval == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); - coex_dm->tdma_adj_type = 6; + coex_dm->ps_tdma_du_adj_type = 6; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); - coex_dm->tdma_adj_type = 7; + coex_dm->ps_tdma_du_adj_type = 7; } } else { if (max_interval == 1) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); - coex_dm->tdma_adj_type = 1; + coex_dm->ps_tdma_du_adj_type = 1; } else if (max_interval == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); - coex_dm->tdma_adj_type = 2; + coex_dm->ps_tdma_du_adj_type = 2; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); - coex_dm->tdma_adj_type = 3; + coex_dm->ps_tdma_du_adj_type = 3; } } } @@ -1804,11 +1804,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, /* if current PsTdma not match with the recorded one (scan, dhcp, ...), * then we have to adjust it back to the previous recorded one. */ - if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) { + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", - coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); @@ -1816,7 +1816,7 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, if (!scan && !link && !roam) btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, - coex_dm->tdma_adj_type); + coex_dm->ps_tdma_du_adj_type); else RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 5bcaeceada9c3..9f41206b20ed8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -84,7 +84,7 @@ struct coex_dm_8723b_2ant { u8 pre_ps_tdma; u8 cur_ps_tdma; u8 ps_tdma_para[5]; - u8 tdma_adj_type; + u8 ps_tdma_du_adj_type; bool reset_tdma_adjust; bool auto_tdma_adjust; bool pre_ps_tdma_on; From 5a347a48467b3c94ad66ead8addb8a29f117dc59 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:56 -0500 Subject: [PATCH 059/201] rtlwifi: btcoex: 23b 2ant: detect ap num and set GNT_BT properly If ap num < 10, let wifi and bt transmit simultaneously, otherwise set wifi into standy when bt is transmitting Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 30b2b93e92cac..eaf909295a694 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -2831,6 +2831,7 @@ void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, u8 h2c_parameter[3] = {0}; u32 wifi_bw; u8 wifi_central_chnl; + u8 ap_num = 0; if (BTC_MEDIA_CONNECT == type) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -2848,10 +2849,16 @@ void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, h2c_parameter[1] = wifi_central_chnl; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - if (BTC_WIFI_BW_HT40 == wifi_bw) + if (wifi_bw == BTC_WIFI_BW_HT40) { h2c_parameter[2] = 0x30; - else - h2c_parameter[2] = 0x20; + } else { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + if (ap_num < 10) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } } coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; From 1712952beabb4f8f5071336b4cc744365efc9b2b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:57 -0500 Subject: [PATCH 060/201] rtlwifi: btcoex: 23b 2ant: more cases for adjusting tdma duration These cases are for the btcoex to tune the performance Signed-off-by: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 766 ++++++++++++++++++ 1 file changed, 766 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index eaf909295a694..dadcddb53557e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1638,6 +1638,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, NORMAL_EXEC, true, 14); coex_dm->ps_tdma_du_adj_type = 14; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, @@ -1655,6 +1660,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, NORMAL_EXEC, true, 10); coex_dm->ps_tdma_du_adj_type = 10; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, @@ -1674,6 +1684,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, NORMAL_EXEC, true, 6); coex_dm->ps_tdma_du_adj_type = 6; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, @@ -1691,6 +1706,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, NORMAL_EXEC, true, 2); coex_dm->ps_tdma_du_adj_type = 2; + } else if (max_interval == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; } else { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, @@ -1796,6 +1816,752 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 71) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } } RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, From b59f02fb7f44cd9c7b159f87c84c1e53e00e03a2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:58 -0500 Subject: [PATCH 061/201] rtlwifi: btcoex: 23b 2ant: fix PTA unstable problem when hw init In the hardware initialisation stage, the PTA circuits may be unstable, so we reset it after 6 secs to fix the problem. Signed-off-by: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 41 +++++++------------ .../rtlwifi/btcoexist/halbtc8723b2ant.h | 2 + 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index dadcddb53557e..e0b6dfa938fa1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3282,12 +3282,14 @@ void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) /* Antenna config */ btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, false); + coex_sta->dis_ver_info_cnt = 0; + /* PTA parameter */ btc8723b2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); /* Enable counter statistics */ /* 0x76e[3] = 1, WLAN_ACT controlled by PTA */ - btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } @@ -3827,36 +3829,21 @@ void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist) void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - struct btc_board_info *board_info = &btcoexist->board_info; - struct btc_stack_info *stack_info = &btcoexist->stack_info; - static u8 dis_ver_info_cnt; - u32 fw_ver = 0, bt_patch_ver = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); - if (dis_ver_info_cnt <= 5) { - dis_ver_info_cnt += 1; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", - board_info->pg_ant_num, - board_info->btdm_ant_num, - board_info->btdm_ant_pos); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], BT stack/ hci ext ver = %s / %d\n", - stack_info->profile_notified ? "Yes" : "No", - stack_info->hci_version); - btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, - &bt_patch_ver); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], CoexVer/ fw_ver/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", - glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, - fw_ver, bt_patch_ver, bt_patch_ver); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], ****************************************************************\n"); + if (coex_sta->dis_ver_info_cnt <= 5) { + coex_sta->dis_ver_info_cnt += 1; + if (coex_sta->dis_ver_info_cnt == 3) { + /* Antenna config to set 0x765 = 0x0 (GNT_BT control by + * PTA) after initial + */ + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Set GNT_BT control by PTA\n"); + btc8723b2ant_set_ant_path( + btcoexist, BTC_ANT_WIFI_AT_MAIN, false, false); + } } #if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 9f41206b20ed8..57eac223bcbdb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -167,6 +167,8 @@ struct coex_sta_8723b_2ant { u32 crc_err_11n_agg; bool force_lps_on; + u8 dis_ver_info_cnt; + u8 a2dp_bit_pool; }; From 609d59acb68ab5175768b818438ea2c95ab9a980 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:49:59 -0500 Subject: [PATCH 062/201] rtlwifi: btcoex: 23b 2ant: add pnp notidy to avoid LPS/IPS mismatch When driver is going to sleep, it does not leave LPS/IPS, thus the BTCoex may have mismatch when driver wakes up. To avoid that, BTCoex needs to clear the IPS/LPS state when it receives a pnp notify, then it can properly set up the hw when driver wakes up. Signed-off-by: Yan-Hsuan Chuang Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index e0b6dfa938fa1..d599e659930c2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3826,6 +3826,33 @@ void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist) ex_btc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); } +void ex_btc8723b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); + + if (pnp_state == BTC_WIFI_PNP_SLEEP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to SLEEP\n"); + + /* Driver do not leave IPS/LPS when driver is going to sleep, so + * BTCoexistence think wifi is still under IPS/LPS + * + * BT should clear UnderIPS/UnderLPS state to avoid mismatch + * state after wakeup. + */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + } else if (pnp_state == BTC_WIFI_PNP_WAKE_UP) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Pnp notify to WAKE UP\n"); + ex_btc8723b2ant_init_hwconfig(btcoexist); + btc8723b2ant_init_coex_dm(btcoexist); + btc8723b2ant_query_bt_info(btcoexist); + } +} + void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; From 684df42cd59711d9077ca4a1980c0b9b084c0b4c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:00 -0500 Subject: [PATCH 063/201] rtlwifi: btcoex: 23b 2ant: check more cases when bt is queuing If bt is queing, we need to set the packet priority properly. Originally we only consider if wifi was connected or not, but now we also consider if bt is under abnormal scan or wifi is scanning, roaming or linking, and set the coex table. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 24 ++++++++++++++++--- .../rtlwifi/btcoexist/halbtc8723b2ant.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index d599e659930c2..31bfc4bb2bd52 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1464,17 +1464,35 @@ static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) { + struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false; bool low_pwr_disable = true; + bool scan = false, link = false, roam = false; btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); - if (wifi_connected) { - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if (coex_sta->bt_abnormal_scan) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if (scan || link || roam) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi link process + BT Inq/Page!!\n"); + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + } else if (wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); } else { btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 57eac223bcbdb..f5e091ff4b591 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -137,6 +137,7 @@ struct coex_sta_8723b_2ant { bool a2dp_exist; bool hid_exist; bool pan_exist; + bool bt_abnormal_scan; bool under_lps; bool under_ips; From a0f430b3eaefc180b9b04f3579ed90a354765f39 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:01 -0500 Subject: [PATCH 064/201] rtlwifi: btcoex: 23b 2ant: workaround for bt a2dp and hid For a2dp and hid, we need extra process to avoid voice degradation Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 31bfc4bb2bd52..55dabe050f873 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1035,6 +1035,8 @@ static void btc8723b2ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1, { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[5]; + if ((coex_sta->a2dp_exist) && (coex_sta->hid_exist)) + byte5 = byte5 | 0x1; h2c_parameter[0] = byte1; h2c_parameter[1] = byte2; From 3b4fa04d8efdf24f331e1d590090b8cfe9007182 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:02 -0500 Subject: [PATCH 065/201] rtlwifi: btcoex: 23b 2ant: tell fw if external or internal switch is used Some chips use an external antenna switch, but fw may not realize it. Here we tell fw exactly that which type of switch we are using. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 55dabe050f873..ec95f0097dfc9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1106,14 +1106,19 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; - h2c_parameter[1] = 1; /* ext switch type */ - btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, - h2c_parameter); - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); } else { /* tell firmware "antenna inverse" */ h2c_parameter[0] = 1; } + + if (use_ext_switch) { + /* ext switch type */ + h2c_parameter[1] = 1; + } else { + /* int switch type */ + h2c_parameter[1] = 0; + } + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); } else { if (fw_ver >= 0x180000) { /* Use H2C to set GNT_BT to "Control by PTA"*/ From bcd37f4a0831fb4f3f7e1c9c7baccdf3d97b7064 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:03 -0500 Subject: [PATCH 066/201] rtlwifi: btcoex: 23b 2ant: let bt transmit when hw initialisation done During hw initialisation, wifi may be ready after bt has already been ready, which causes bt to act abnormally. To avoid this, set GNT_BT to high during hw init. Signed-off-by: Yan-Hsuan Chuang Cc: Stable Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index ec95f0097dfc9..16a4a5c4f0240 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1083,12 +1083,7 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, use_ext_switch = true; if (init_hwcfg) { - /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */ - u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); - u32tmp &= ~BIT23; - u32tmp |= BIT24; - btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); - + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x39, 0x8, 0x1); btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); @@ -1103,6 +1098,12 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); } + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + /* WiFi TRx Mask off */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x1, 0xfffff, 0x0); + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { /* tell firmware "no antenna inverse" */ h2c_parameter[0] = 0; @@ -1125,17 +1126,23 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, h2c_parameter[0] = 0; btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, h2c_parameter); - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + } else { + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x0); } } /* ext switch setting */ if (use_ext_switch) { + if (init_hwcfg) { + /* 0x4c[23] = 0, 0x4c[24] = 1 Ant controlled by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp |= BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + /* fixed internal switch S1->WiFi, S0->BT */ - if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); - else - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); switch (antpos_type) { case BTC_ANT_WIFI_AT_MAIN: @@ -1149,9 +1156,18 @@ static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, 0x92c, 0x3, 0x2); break; } - } else { /* internal switch */ - /* fixed ext switch */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); + } else { + /* internal switch */ + if (init_hwcfg) { + /* 0x4c[23] = 0, 0x4c[24] = 1 Ant controlled by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT23; + u32tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + /* fixed ext switch, S1->Main, S0->Aux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x0); switch (antpos_type) { case BTC_ANT_WIFI_AT_MAIN: /* fixed internal switch S1->WiFi, S0->BT */ @@ -1458,6 +1474,7 @@ static void btc8723b2ant_coex_alloff(struct btc_coexist *btcoexist) static void btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) { /* force to reset coex mechanism*/ + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); From a8570896b962dc2b8e7787c59a45521e64b187e2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:04 -0500 Subject: [PATCH 067/201] rtlwifi: btcoex: 23b 2ant: turn off ps and tdma mechanism when in concurrent mode When wifi is in concurrent mode, we can not distinguish if it is the real PS or just a fake one by sending null data, so we turn it off in case of miracast scenario. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 46 +++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 2 files changed, 47 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 16a4a5c4f0240..654886598482c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3168,10 +3168,29 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) } } +static void btc8723b2ant_action_wifi_multi_port(struct btc_coexist *btcoexist) +{ + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + btc8723b2ant_sw_mechanism(btcoexist, false, false, false, false); + + /* hw all off */ + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +} + static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool miracast_plus_bt = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], RunCoexistMechanism()===>\n"); @@ -3203,6 +3222,33 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + btc8723b2ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + coex_dm->cur_algorithm = algorithm; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Algorithm = %d\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index d7ba6ad1e66f9..022658cafbcae 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -249,6 +249,7 @@ enum btc_set_type { BTC_SET_BL_TO_REJ_AP_AGG_PKT, BTC_SET_BL_BT_CTRL_AGG_SIZE, BTC_SET_BL_INC_SCAN_DEV_NUM, + BTC_SET_BL_MIRACAST_PLUS_BT, /* type u1Byte */ BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, From c5e2113613bcf2693a9d7e54e1f54b27194a935c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:05 -0500 Subject: [PATCH 068/201] rtlwifi: btcoex: 23b 2ant: turn off antenna when rssi is too high/low For 2-antenna combo card, the signal of the neighbor antenna could be over noise level and cause be severe interference. So we monitor the rssi and turn off one of the antennas when the other is transmitting and the rssi level is beyond a threshold. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 332 +++++++++++++++--- .../rtlwifi/btcoexist/halbtc8723b2ant.h | 7 + 2 files changed, 282 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 654886598482c..e722c7cd16738 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -369,6 +369,8 @@ static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) static bool pre_bt_hs_on; bool wifi_busy = false, under_4way = false, bt_hs_on = false; bool wifi_connected = false; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + u8 tmp; btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); @@ -392,6 +394,15 @@ static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) pre_bt_hs_on = bt_hs_on; return true; } + + tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + wifi_rssi_state = + btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, tmp, 0); + + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_LOW)) + return true; } return false; @@ -1186,8 +1197,16 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, { struct rtl_priv *rtlpriv = btcoexist->adapter; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 wifi_rssi_state, bt_rssi_state; s8 wifi_duration_adjust = 0x0; u8 tdma_byte4_modify = 0x0; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], %s turn %s PS TDMA, type=%d\n", @@ -1196,6 +1215,15 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, coex_dm->cur_ps_tdma_on = turn_on; coex_dm->cur_ps_tdma = type; + if (!(BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) && turn_on) { + /* for WiFi RSSI low or BT RSSI low */ + type = type + 100; + coex_dm->is_switch_to_1dot5_ant = true; + } else { + coex_dm->is_switch_to_1dot5_ant = false; + } + if (!force_exec) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", @@ -1346,6 +1374,12 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); break; + + case 23: + case 123: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x35, + 0x03, 0x71, 0x10); + break; case 71: btc8723b2ant_set_fw_ps_tdma( btcoexist, 0xe3, 0x3c + wifi_duration_adjust, @@ -1367,6 +1401,37 @@ static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, btcoexist, 0xd3, 0x2d + wifi_duration_adjust, 0x03, 0x70, 0x50 | tdma_byte4_modify); break; + case 103: + case 107: + case 111: + case 115: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1c, + 0x03, 0x70, + 0x50 | tdma_byte4_modify); + break; + case 104: + case 108: + case 112: + case 116: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x10, + 0x03, 0x70, + 0x50 | tdma_byte4_modify); + break; + case 109: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0xf1, + 0x90 | tdma_byte4_modify); + break; + case 121: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, + 0x90 | tdma_byte4_modify); + break; + case 22: + case 122: + btc8723b2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x35, + 0x03, 0x71, 0x11); + break; } } else { /* disable PS tdma */ @@ -2634,17 +2699,25 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, /* SCO only or SCO+PAN(HS) */ static void btc8723b2ant_action_sco(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state; + u8 wifi_rssi_state, bt_rssi_state; u32 wifi_bw; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state( + btcoexist, 2, BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, + 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (BTC_WIFI_BW_LEGACY == wifi_bw) @@ -2683,16 +2756,22 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) { u8 wifi_rssi_state, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); - btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x5); + btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (wifi_bw == BTC_WIFI_BW_LEGACY) @@ -2738,12 +2817,12 @@ static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; u8 ap_num = 0; + u8 tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, - 1, 2, 40, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, 40, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); @@ -2774,7 +2853,20 @@ static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) @@ -2808,18 +2900,37 @@ static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist) static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2); @@ -2848,12 +2959,17 @@ static void btc8723b2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2865,7 +2981,15 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) else btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 10); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 10); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) @@ -2899,20 +3023,25 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) /* PAN(HS) only */ static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) - btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); else btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); @@ -2944,12 +3073,17 @@ static void btc8723b2ant_action_pan_hs(struct btc_coexist *btcoexist) /* PAN(EDR) + A2DP */ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2961,6 +3095,12 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) else btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -3001,12 +3141,17 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; - - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); @@ -3016,27 +3161,32 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) else btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { if (BTC_WIFI_BW_HT40 == wifi_bw) { btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3); - btc8723b2ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 11); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); } else { btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8723b2ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, 7); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); } btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); } else { btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 11); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); @@ -3067,12 +3217,17 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) /* HID + A2DP + PAN(EDR) */ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -3084,9 +3239,18 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) else btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { @@ -3124,12 +3288,18 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; + u8 ap_num = 0; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; - wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, 29, 0); + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 3, tmp, 37); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -3138,13 +3308,61 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + if (wifi_bw == BTC_WIFI_BW_LEGACY) { + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else { + /* only 802.11N mode we have to dec bt power to 4 degree */ + if (BTC_RSSI_HIGH(bt_rssi_state)) { + /* need to check ap Number of Not */ + if (ap_num < 10) + btc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 4); + else + btc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 2); + } else if (BTC_RSSI_MEDIUM(bt_rssi_state)) { + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + } else { + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } + } - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) - btc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); - else - btc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + if (BTC_RSSI_HIGH(bt_rssi_state)) { + if (ap_num < 10) + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 1); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else { + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 18); + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + btcoexist->btc_write_4byte(btcoexist, 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, 0x01010000); + + if (ap_num < 10) + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 1); + else + btc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + } /* sw mechanism */ if (BTC_WIFI_BW_HT40 == wifi_bw) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index f5e091ff4b591..2c21134824817 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -41,6 +41,11 @@ #define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 +/* WiFi RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES 42 +/* BT RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES 46 + enum BT_INFO_SRC_8723B_2ANT { BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, @@ -127,6 +132,8 @@ struct coex_dm_8723b_2ant { u8 pre_rpwm; u8 cur_rpwm; + bool is_switch_to_1dot5_ant; + u8 switch_thres_offset; bool need_recover_0x948; u16 backup_0x948; }; From 83cded7a1ef075ecebc08d5d92f2891288dbbe30 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 4 Apr 2017 11:50:06 -0500 Subject: [PATCH 069/201] rtlwifi: btcoex: 23b 2ant: set coex table when wifi is linking When wifi is under linking process, those packets are important. Mark them as high priority to protect the linking process Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index e722c7cd16738..c9f04454b19b9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1592,6 +1592,27 @@ static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) btc8723b2ant_sw_mechanism(btcoexist, false, false, false, false); } +static void btc8723b2ant_action_wifi_link_process(struct btc_coexist + *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 u32tmp; + u8 u8tmpa, u8tmpb; + + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + btc8723b2ant_sw_mechanism(btcoexist, false, false, false, false); + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 0x948 = 0x%x, 0x765 = 0x%x, 0x76e = 0x%x\n", + u32tmp, u8tmpa, u8tmpb); +} + static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -3409,6 +3430,7 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) u32 wifi_link_status = 0; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool miracast_plus_bt = false; + bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], RunCoexistMechanism()===>\n"); @@ -3440,6 +3462,17 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under Link Process !!\n"); + btc8723b2ant_action_wifi_link_process(btcoexist); + return; + } + /* for P2P */ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); From 470eec1a3d0ab2087d42b1b0a9dd1d4c04b1824f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:48 -0500 Subject: [PATCH 070/201] rtlwifi: btcoex: 23b 2ant: set coex table when wifi is idle When wifi is idle, the bt should have more resource to transmit. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index c9f04454b19b9..327609e3a3097 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1613,6 +1613,47 @@ static void btc8723b2ant_action_wifi_link_process(struct btc_coexist u32tmp, u8tmpa, u8tmpb); } +static bool btc8723b2ant_action_wifi_idle_process(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; + u8 tmp = BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset - coex_dm->switch_thres_offset; + + wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, + tmp, 0); + tmp = BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset - coex_dm->switch_thres_offset; + bt_rssi_state = btc8723b2ant_bt_rssi_state(btcoexist, 2, tmp, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* office environment */ + if (BTC_RSSI_HIGH(wifi_rssi_state1) && (coex_sta->hid_exist) && + (coex_sta->a2dp_exist)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi idle process for BT HID+A2DP exist!!\n"); + + btc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + btc8723b2ant_sw_mechanism(btcoexist, false, false, false, + false); + btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + return true; + } + + btc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x18); + return false; +} + static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1710,26 +1751,12 @@ static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist) "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); common = false; } else { - if (bt_hs_on) - return false; - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); - btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, - 0x1, 0xfffff, 0x0); - btc8723b2ant_coex_table_with_type(btcoexist, - NORMAL_EXEC, - 7); - btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 21); - btc8723b2ant_fw_dac_swing_lvl(btcoexist, - NORMAL_EXEC, - 0xb); - btc8723b2ant_sw_mechanism(btcoexist, false, - false, false, - false); - common = true; + common = + btc8723b2ant_action_wifi_idle_process( + btcoexist); } } } From 2037b83c12d1535cab7e73181c34e353ffb94700 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:49 -0500 Subject: [PATCH 071/201] rtlwifi: btcoex: 23b 2ant: treat too many low prio packets as retry Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 327609e3a3097..82a5e5357cb7d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -1884,6 +1884,11 @@ static void btc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, } else { /*accquire the BT TRx retry count from BT_Info byte2*/ retry_count = coex_sta->bt_retry_cnt; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], retry_count = %d\n", retry_count); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, From acb9c779ecc56c27a15f7ef0400d0509802357b6 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:50 -0500 Subject: [PATCH 072/201] rtlwifi: btcoex: 23b 2ant: remove debugging code for 0x948 Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 6 ------ .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 82a5e5357cb7d..9c169d094b51e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3486,12 +3486,6 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) "[BTCoex], BT is under inquiry/page scan !!\n"); btc8723b2ant_action_bt_inquiry(btcoexist); return; - } else { - if (coex_dm->need_recover_0x948) { - coex_dm->need_recover_0x948 = false; - btcoexist->btc_write_2byte(btcoexist, 0x948, - coex_dm->backup_0x948); - } } btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 2c21134824817..9e29f85304cc5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -134,8 +134,6 @@ struct coex_dm_8723b_2ant { bool is_switch_to_1dot5_ant; u8 switch_thres_offset; - bool need_recover_0x948; - u16 backup_0x948; }; struct coex_sta_8723b_2ant { From ae889ebc76c95892dc7b10f15bf7a5cb9e1c6684 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:51 -0500 Subject: [PATCH 073/201] rtlwifi: btcoex: 23b 2ant: need those information when scan For scan notify, we need to supervise some registers to make sure that coexistence is operating as we expected. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 9c169d094b51e..93dbbc507ba16 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3934,6 +3934,12 @@ void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; + u32 u32tmp; + u8 u8tmpa, u8tmpb; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); if (BTC_SCAN_START == type) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -3943,6 +3949,10 @@ void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], SCAN FINISH notify\n"); btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &coex_sta->scan_ap_num); + + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb); } void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) From 7558668d05366b5747cd5223e87913083450b8bf Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:52 -0500 Subject: [PATCH 074/201] rtlwifi: btcoex: 23b 2ant: wifi is not actually off in mp mode In mp mode, the wifi will not turn off and still has control of the PTA, so the driver needs to distinguish whether it is mp mode or not Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 10 ++++++++++ .../wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 93dbbc507ba16..70f21059ddc30 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3606,6 +3606,7 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist) { + bool is_in_mp_mode = false; u8 h2c_parameter[2] = {0}; u32 fw_ver = 0; @@ -3623,6 +3624,15 @@ static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist) } else { btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + &is_in_mp_mode); + if (!is_in_mp_mode) + /* BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + else + /* BT select s0/s1 is controlled by WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); } /********************************************************************* diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 022658cafbcae..0b90e7f0b722c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -205,6 +205,7 @@ enum btc_get_type { BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, BTC_GET_BL_WIFI_UNDER_B_MODE, BTC_GET_BL_EXT_SWITCH, + BTC_GET_BL_WIFI_IS_IN_MP_MODE, /* type s4Byte */ BTC_GET_S4_WIFI_RSSI, From 4e6becc0448b936c24bccacf39a94f8a1cf81e21 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:53 -0500 Subject: [PATCH 075/201] rtlwifi: btcoex: 23b 2ant: power on settings for coex When power on, the wifi could be initiating, force the antenna to transmit bt packets to avoid bt unstable problems Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 31 +++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 1 + 2 files changed, 32 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 70f21059ddc30..0f3d04529ff2d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3669,6 +3669,37 @@ void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } +void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp = 0x0; + u32 value = 0; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT0 | BIT1); + + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + } +} + void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 0b90e7f0b722c..5a34cd895e444 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -139,6 +139,7 @@ struct btc_board_info { u8 pg_ant_num; /* pg ant number */ u8 btdm_ant_num; /* ant number for btdm */ u8 btdm_ant_pos; + u8 single_ant_path; /* current used for 8723b only, 1=>s0, 0=>s1 */ bool bt_exist; }; From 6dcf041eabd1136abc46574092985acc86be99c0 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:54 -0500 Subject: [PATCH 076/201] rtlwifi: btcoex: 23b 2ant: before firmware ready settings Before firmware is ready, set GNT_BT to high to let bt transmit Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 38 +++++++++++++++++++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 2 + 2 files changed, 40 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 0f3d04529ff2d..06f70944bdac4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3700,6 +3700,44 @@ void ex_btc8723b2ant_power_on_setting(struct btc_coexist *btcoexist) } } +void ex_btc8723b2ant_pre_load_firmware(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /** + * S0 or S1 setting and Local register setting(By this fw can get + * ant number, S0/S1, ... info) + * + * Local setting bit define + * BIT0: "0" : no antenna inverse; "1" : antenna inverse + * BIT1: "0" : internal switch; "1" : external switch + * BIT2: "0" : one antenna; "1" : two antennas + * + * NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and + * BIT2 = 0 + */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index 5a34cd895e444..d31e6df5b1bf3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -369,6 +369,7 @@ typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data); typedef void (*bfp_btc_w4)(void *btc_context, u32 reg_addr, u32 data); +typedef void (*bfp_btc_local_reg_w1)(void *btc_context, u32 reg_addr, u8 data); typedef void (*bfp_btc_wr_1byte_bit_mask)(void *btc_context, u32 reg_addr, u8 bit_mask, u8 data); @@ -496,6 +497,7 @@ struct btc_coexist { bfp_btc_w2 btc_write_2byte; bfp_btc_r4 btc_read_4byte; bfp_btc_w4 btc_write_4byte; + bfp_btc_local_reg_w1 btc_write_local_reg_1byte; bfp_btc_set_bb_reg btc_set_bb_reg; bfp_btc_get_bb_reg btc_get_bb_reg; From 2e6689824a4c6d4275662f989c65a529c6f7a9f2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:55 -0500 Subject: [PATCH 077/201] rtlwifi: btcoex: 23b 2ant: fine tune for bt pan_edr_a2dp If we don't limit the rx aggregation size, and set tdma instead, the bt profile can get more stable. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 06f70944bdac4..a76c8d20e0935 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3140,7 +3140,6 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); - btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) @@ -3167,7 +3166,7 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) false, 3); } else { btc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); - btc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 3); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); } /* sw mechanism */ From 110944027627071cab79c968dbb8dfec3b337b54 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:56 -0500 Subject: [PATCH 078/201] rtlwifi: btcoex: 23b 2ant: fine tune for bt hid_a2dp Let bt control the aggregation size to improve stability. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index a76c8d20e0935..9092de2d2c7c8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3355,7 +3355,7 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); - btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + btc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x5); btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); From 588a290b4642de9996a83d95474528f08ffe882a Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:57 -0500 Subject: [PATCH 079/201] rtlwifi: btcoex: 23b 2ant: notify more bt information These bt information are displayed in display coex Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8723b2ant.c | 20 +++++++++++++++++++ .../rtlwifi/btcoexist/halbtc8723b2ant.h | 2 ++ .../realtek/rtlwifi/btcoexist/halbtcoutsrc.h | 15 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 9092de2d2c7c8..1c823a71ce9f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -4145,9 +4145,19 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_remote_name_req = true; + else + coex_sta->c2h_bt_remote_name_req = false; + if (coex_sta->bt_info_c2h[rsp_source][1] == 0x49) coex_sta->a2dp_bit_pool = coex_sta->bt_info_c2h[rsp_source][6]; @@ -4222,6 +4232,16 @@ void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->sco_exist = true; else coex_sta->sco_exist = false; + + if ((!coex_sta->hid_exist) && + (!coex_sta->c2h_bt_inquiry_page) && + (!coex_sta->sco_exist)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) { + coex_sta->hid_exist = true; + bt_info = bt_info | 0x28; + } + } } btc8723b2ant_update_bt_link_info(btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h index 9e29f85304cc5..18a35c7faba92 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -151,12 +151,14 @@ struct coex_sta_8723b_2ant { u32 low_priority_tx; u32 low_priority_rx; u8 bt_rssi; + bool bt_tx_rx_mask; u8 pre_bt_rssi_state; u8 pre_wifi_rssi_state[4]; bool c2h_bt_info_req_sent; u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX]; bool c2h_bt_inquiry_page; + bool c2h_bt_remote_name_req; u8 bt_retry_cnt; u8 bt_info_ext; u32 pop_event_cnt; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index d31e6df5b1bf3..c8271135aaaae 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -66,6 +66,15 @@ #define BTC_ANT_WIFI_AT_CPL_MAIN 0 #define BTC_ANT_WIFI_AT_CPL_AUX 1 +enum btc_bt_reg_type { + BTC_BT_REG_RF = 0, + BTC_BT_REG_MODEM = 1, + BTC_BT_REG_BLUEWIZE = 2, + BTC_BT_REG_VENDOR = 3, + BTC_BT_REG_LE = 4, + BTC_BT_REG_MAX +}; + enum btc_chip_interface { BTC_INTF_UNKNOWN = 0, BTC_INTF_PCI = 1, @@ -251,6 +260,7 @@ enum btc_set_type { BTC_SET_BL_TO_REJ_AP_AGG_PKT, BTC_SET_BL_BT_CTRL_AGG_SIZE, BTC_SET_BL_INC_SCAN_DEV_NUM, + BTC_SET_BL_BT_TX_RX_MASK, BTC_SET_BL_MIRACAST_PLUS_BT, /* type u1Byte */ @@ -392,6 +402,9 @@ typedef bool (*bfp_btc_get)(void *btcoexist, u8 get_type, void *out_buf); typedef bool (*bfp_btc_set)(void *btcoexist, u8 set_type, void *in_buf); +typedef void (*bfp_btc_set_bt_reg)(void *btc_context, u8 reg_type, u32 offset, + u32 value); + typedef void (*bfp_btc_disp_dbg_msg)(void *btcoexist, u8 disp_type); struct btc_bt_info { @@ -511,6 +524,8 @@ struct btc_coexist { bfp_btc_get btc_get; bfp_btc_set btc_set; + + bfp_btc_set_bt_reg btc_set_bt_reg; }; bool halbtc_is_wifi_uplink(struct rtl_priv *adapter); From f4a23e194ef370baddf3b3ea74b418fa63f08869 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 6 Apr 2017 15:19:58 -0500 Subject: [PATCH 080/201] rtlwifi: btcoex: 23b 2ant: some hi-prio pkt will cause hid_exist Clear the hid_exist flag by monitoring the packet counter. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 1c823a71ce9f5..2f3946be4ce29 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -4329,6 +4329,7 @@ void ex_btc8723b2ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], ==========================Periodical===========================\n"); @@ -4352,6 +4353,13 @@ void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) btc8723b2ant_monitor_bt_ctr(btcoexist); btc8723b2ant_monitor_wifi_ctr(btcoexist); + /* for some BT speakers that High-Priority pkts appear before + * playing, this will cause HID exist + */ + if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && + (bt_link_info->hid_exist)) + bt_link_info->hid_exist = false; + if (btc8723b2ant_is_wifi_status_changed(btcoexist) || coex_dm->auto_tdma_adjust) btc8723b2ant_run_coexist_mechanism(btcoexist); From 1bdd83392f7f7719e99bf8d2c0ead60639ce6f3b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:22:57 -0500 Subject: [PATCH 081/201] rtlwifi: btcoex: 21a 1ant: fw settings for softap mode For ap mode, adjust fw settings to operate properly. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 6f6ab0738fbb3..5b8f4ed5ce625 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -843,18 +843,35 @@ static void btc8821a1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, u8 byte1, { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + bool ap_enable = false; - h2c_parameter[0] = byte1; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT4 && !(byte1 & BIT5)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], FW for 1Ant AP mode\n"); + real_byte1 &= ~BIT4; + real_byte1 |= BIT5; + + real_byte5 |= BIT5; + real_byte5 &= ~BIT6; + } + } + + h2c_parameter[0] = real_byte1; h2c_parameter[1] = byte2; h2c_parameter[2] = byte3; h2c_parameter[3] = byte4; - h2c_parameter[4] = byte5; + h2c_parameter[4] = real_byte5; - coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[0] = real_byte1; coex_dm->ps_tdma_para[1] = byte2; coex_dm->ps_tdma_para[2] = byte3; coex_dm->ps_tdma_para[3] = byte4; - coex_dm->ps_tdma_para[4] = byte5; + coex_dm->ps_tdma_para[4] = real_byte5; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", From 19baccc4561fc7dc18ff79e14bdfa86bd0b34abc Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:22:58 -0500 Subject: [PATCH 082/201] rtlwifi: btcoex: 21a 1ant: add function to check wifi status This function checks if wifi has changed its statusi. It will be needed in the future. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 5b8f4ed5ce625..65c455bfd8fbc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -424,6 +424,39 @@ static void btc8821a1ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } +bool btc8821a1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = true; + static bool pre_under_4way = true; + static bool pre_bt_hs_on = true; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + static void btc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; From 3121b4ddd1817b7177c0747835e652ef9b733cd9 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:22:59 -0500 Subject: [PATCH 083/201] rtlwifi: btcoex: 21a 1ant: coex table setting for new fw For newer fw, the coex table setting needs to be modified to operate correctly. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 65c455bfd8fbc..3a117eaf1b218 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -806,24 +806,24 @@ static void btc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist, 0x5a5a5a5a, 0xffffff, 0x3); break; case 3: - btc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555, + btc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, 0xaaaaaaaa, 0xffffff, 0x3); break; case 4: - btc8821a1ant_coex_table(btcoexist, force_exec, 0xffffffff, - 0xffffffff, 0xffffff, 0x3); + btc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); break; case 5: - btc8821a1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, - 0x5fff5fff, 0xffffff, 0x3); + btc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0xaaaa5a5a, 0xffffff, 0x3); break; case 6: - btc8821a1ant_coex_table(btcoexist, force_exec, 0x55ff55ff, - 0x5a5a5a5a, 0xffffff, 0x3); + btc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa5a5a, 0xffffff, 0x3); break; case 7: - btc8821a1ant_coex_table(btcoexist, force_exec, 0x5afa5afa, - 0x5afa5afa, 0xffffff, 0x3); + btc8821a1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, 0xffffff, 0x3); break; default: break; From f0c40cf09dd12e8ebd1a05695d41eacef007076e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:00 -0500 Subject: [PATCH 084/201] rtlwifi: btcoex: 21a 1ant: mask profile bit for connect-ilde Mask out the connect-idle bit. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 3a117eaf1b218..88bf70f276691 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2606,7 +2606,12 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, btc8821a1ant_update_bt_link_info(btcoexist); - if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) { + /* mask profile bit for connect-ilde identification + * (for CSR case: A2DP idle --> 0x41) + */ + bt_info = bt_info & 0x1f; + + if (!(bt_info & BT_INFO_8821A_1ANT_B_CONNECTION)) { coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); From e605103c443eaafdb760aecf00d512f8b6d988f0 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:01 -0500 Subject: [PATCH 085/201] rtlwifi: btcoex: 21a 1ant: remove setting for 2 antennas The antenna position setting is useless for 1 antenna chip. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 88bf70f276691..b84c1a5be40a2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -994,9 +994,6 @@ static void btc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); - /* Main Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, - 0x1, 0x1); } else { /* tell firmware "no antenna inverse" * WRONG firmware antenna control code, need fw to fix @@ -1005,9 +1002,6 @@ static void btc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, h2c_parameter[1] = 1; btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); - /* Aux Ant to BT for IPS case 0x4c[23] = 1 */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, - 0x1, 0x0); } } else if (wifi_off) { /* 0x4c[24:23] = 00, Set Antenna control From 4f78287e5ed9ca9326b0df7a7dcf048a7d32be67 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:02 -0500 Subject: [PATCH 086/201] rtlwifi: btcoex: 21a 1ant: set antenna control path for PTA Set antenna control path if PTA is in control of the packet path of wifi and bt. If wifi is turned off, tell the PTA about it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index b84c1a5be40a2..5b374c7728baa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1011,11 +1011,18 @@ static void btc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, u4_tmp &= ~BIT23; u4_tmp &= ~BIT24; btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); + + /* 0x765 = 0x18 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + } else { + /* 0x765 = 0x0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); } /* ext switch setting */ switch (ant_pos_type) { case BTC_ANT_PATH_WIFI: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); @@ -1024,6 +1031,7 @@ static void btc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, 0x30, 0x2); break; case BTC_ANT_PATH_BT: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); @@ -1033,6 +1041,7 @@ static void btc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, break; default: case BTC_ANT_PATH_PTA: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x66); if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); From 06a75324d5436b99c3a727d32b964732835e86a1 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:03 -0500 Subject: [PATCH 087/201] rtlwifi: btcoex: 21a 1ant: add multi port action for miracast and P2P To support miracast and P2P, the chip may operate under concurrent mode, In this situation, do not aggregate tx packet and properly set the rx aggregation size. We detect it by monitoring the number of link established. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 5b374c7728baa..cadc0f91af41d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1478,6 +1478,14 @@ static void btc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist) * Non-Software Coex Mechanism start * ***********************************************/ +static +void btc8821a1ant_action_wifi_multi_port(struct btc_coexist *btcoexist) +{ + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + static void btc8821a1ant_action_hs(struct btc_coexist *btcoexist) { @@ -1820,6 +1828,8 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) bool bt_ctrl_agg_buf_size = false; u8 agg_buf_size = 5; u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; bool wifi_under_5g = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -1862,6 +1872,18 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + btc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + btc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); } else { @@ -2337,6 +2359,10 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; + bool bt_ctrl_agg_buf_size = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || @@ -2350,6 +2376,17 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) btc8821a1ant_query_bt_info(btcoexist); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + btc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + btc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + if (coex_sta->c2h_bt_inquiry_page) { btc8821a1ant_action_bt_inquiry(btcoexist); return; @@ -2384,12 +2421,27 @@ void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || btcoexist->bt_info.bt_disabled) return; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + btc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + btc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); if (coex_sta->c2h_bt_inquiry_page) { btc8821a1ant_action_bt_inquiry(btcoexist); @@ -2472,6 +2524,10 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, { struct rtl_priv *rtlpriv = btcoexist->adapter; bool bt_hs_on = false; + bool bt_ctrl_agg_buf_size = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || @@ -2480,6 +2536,17 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, coex_sta->special_pkt_period_cnt = 0; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + btc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + btc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + btc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); if (coex_sta->c2h_bt_inquiry_page) { btc8821a1ant_action_bt_inquiry(btcoexist); From edf8fa7b66f0e7b74806439581b2b5ae72a8b8d3 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:04 -0500 Subject: [PATCH 088/201] rtlwifi: btcoex: 21a 1ant: action when associating/authenticating When wifi is associating or authenticating, set the coex table for wifi to establish link. These packets should have higher priority. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index cadc0f91af41d..05e33d38d49c8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1486,6 +1486,28 @@ void btc8821a1ant_action_wifi_multi_port(struct btc_coexist *btcoexist) btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } +static +void btc8821a1ant_action_wifi_not_connected_asso_auth( + struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->a2dp_exist) || (bt_link_info->pan_exist)) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + static void btc8821a1ant_action_hs(struct btc_coexist *btcoexist) { @@ -1941,10 +1963,15 @@ static void btc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); - if (scan || link || roam) - btc8821a1ant_act_wifi_not_conn_scan(btcoexist); - else + if (scan || link || roam) { + if (scan) + btc8821a1ant_act_wifi_not_conn_scan(btcoexist); + else + btc8821a1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else { btc8821a1ant_action_wifi_not_connected(btcoexist); + } } else { /* wifi LPS/Busy */ btc8821a1ant_action_wifi_connected(btcoexist); From bcdffd050c80a72465a8736aacdd614f583a5fb3 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:05 -0500 Subject: [PATCH 089/201] rtlwifi: btcoex: 21a 1ant: If wifi only, do not initiate coex mechanism If the device has wifi mode only, there is no need to initiate the hardware for wifi and bt coexistence, so just return to avoid it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 05e33d38d49c8..86eab6a4ada2c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1990,7 +1990,7 @@ static void btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) } static void btc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, - bool back_up) + bool back_up, bool wifi_only) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u1_tmp = 0; @@ -1999,6 +1999,9 @@ static void btc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], 1Ant Init HW Config!!\n"); + if (wifi_only) + return; + if (back_up) { coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, 0x430); @@ -2039,9 +2042,9 @@ static void btc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, /************************************************************** * extern function start with ex_btc8821a1ant_ **************************************************************/ -void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist) +void ex_btc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist, bool wifionly) { - btc8821a1ant_init_hw_config(btcoexist, true); + btc8821a1ant_init_hw_config(btcoexist, true, wifionly); } void ex_btc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) @@ -2783,7 +2786,7 @@ void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to WAKE UP\n"); btcoexist->stop_coex_dm = false; - btc8821a1ant_init_hw_config(btcoexist, false); + btc8821a1ant_init_hw_config(btcoexist, false, false); btc8821a1ant_init_coex_dm(btcoexist); btc8821a1ant_query_bt_info(btcoexist); } From 19afb92222af081597747a2fc51638e36968bf4d Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:06 -0500 Subject: [PATCH 090/201] rtlwifi: btcoex: 21a 1ant: move bt_disabled to global struct Move the bt disable flag to a global structure to indicate that bt is turned off. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 24 +++++++++---------- .../rtlwifi/btcoexist/halbtc8821a1ant.h | 1 + 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 86eab6a4ada2c..c6114b32c0ca0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2168,7 +2168,7 @@ void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) "uplink" : "downlink"))); RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", - ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->bt_disabled) ? ("disabled") : ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) ? @@ -2394,9 +2394,10 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) u32 num_of_wifi_link = 0; u8 agg_buf_size = 5; - if (btcoexist->manual_control || - btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, @@ -2456,9 +2457,8 @@ void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) bool bt_ctrl_agg_buf_size = false; u8 agg_buf_size = 5; - if (btcoexist->manual_control || - btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + coex_sta->bt_disabled) return; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, @@ -2508,9 +2508,8 @@ void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, u32 wifi_bw; u8 wifi_central_chnl; - if (btcoexist->manual_control || - btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + coex_sta->bt_disabled) return; if (BTC_MEDIA_CONNECT == type) { @@ -2559,9 +2558,8 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, u32 num_of_wifi_link = 0; u8 agg_buf_size = 5; - if (btcoexist->manual_control || - btcoexist->stop_coex_dm || - btcoexist->bt_info.bt_disabled) + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + coex_sta->bt_disabled) return; coex_sta->special_pkt_period_cnt = 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index 9f50a1427388d..2dec38ab77467 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -140,6 +140,7 @@ struct coex_dm_8821a_1ant { }; struct coex_sta_8821a_1ant { + bool bt_disabled; bool bt_link_exist; bool sco_exist; bool a2dp_exist; From ee828085176ed679d1f8ec4c7ca386b73ab2ee51 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:07 -0500 Subject: [PATCH 091/201] rtlwifi: btcoex: 21a 1ant: consider more cases when bt inquiry With bt inquiry, the wifi may start as a softap or the wifi and bt are busy, we take these scenarios into consider to avoid bt inquiry to degrade the performance of the network Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 75 +++++++++++++++---- .../rtlwifi/btcoexist/halbtc8821a1ant.h | 1 + 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index c6114b32c0ca0..6b08051614eb5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1139,8 +1139,8 @@ static void btc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, 0x18, 0x0, 0x10); break; case 14: - btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, - 0x3, 0x10, 0x10); + btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1e, + 0x3, 0x10, 0x14); break; case 15: btc8821a1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, @@ -1519,27 +1519,46 @@ static void btc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_connected = false; + bool ap_enable = false; + bool wifi_busy = false, bt_busy = false; - btcoexist->btc_get(btcoexist, - BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); - if (!wifi_connected) { + if (!wifi_connected && !coex_sta->wifi_is_high_pri_task) { btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); - } else if ((bt_link_info->sco_exist) || + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->sco_exist) || (bt_link_info->a2dp_exist) || (bt_link_info->hid_only)) { /* SCO/HID-only busy */ btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if ((bt_link_info->a2dp_exist) && (bt_link_info->hid_exist)) { + /* A2DP+HID busy */ + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->pan_exist) || (wifi_busy)) { + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); } else { - btc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, - 0x50, 0x4); - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); } } @@ -1629,11 +1648,35 @@ void btc8821a1ant_action_wifi_not_connected(struct btc_coexist *btcoexist) static void btc8821a1ant_act_wifi_not_conn_scan(struct btc_coexist *btcoexist) { - btc8821a1ant_power_save_state(btcoexist, - BTC_PS_WIFI_NATIVE, 0x0, 0x0); + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + /* tdma and coex table */ + if (coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_SCO_BUSY) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } } static diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h index 2dec38ab77467..1bd1ebe3364eb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -161,6 +161,7 @@ struct coex_sta_8821a_1ant { u8 bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10]; u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX]; bool c2h_bt_inquiry_page; + bool wifi_is_high_pri_task; u8 bt_retry_cnt; u8 bt_info_ext; }; From cb52b118594703db75f6caace7e318aa18a118ba Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:08 -0500 Subject: [PATCH 092/201] rtlwifi: btcoex: 21a 1ant: monitor bt profiling when scan When wifi is scanning and not connected, set the tdma and coex table properly to control the priority of the packets to make the wifi bt coexistence operate smoothly Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 6b08051614eb5..eab04c2bdd3d7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -1481,9 +1481,34 @@ static void btc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist) static void btc8821a1ant_action_wifi_multi_port(struct btc_coexist *btcoexist) { + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); - btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + /* tdma and coex table */ + if (coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_ACL_BUSY) { + if (bt_link_info->a2dp_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + btc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((coex_dm->bt_status == BT_8821A_1ANT_BT_STATUS_SCO_BUSY) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } } static From da0fd9ccb4325bcc95532d15e553bdb355a56e5f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:09 -0500 Subject: [PATCH 093/201] rtlwifi: btcoex: 21a 1ant: do not switch antenna when wifi is under 5G channel When wifi is on a 5G channel, the 5G signal will not interfere bt 2.4G signal, and they can transmit simultaneously, hence there is no need to switch antenna between wifi and bt. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a1ant.c | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index eab04c2bdd3d7..0509ffab9e6ff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -44,6 +44,8 @@ static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant; static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant; static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant; static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant; +static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, + u8 wifi_status); static const char *const glbt_info_src_8821a_1ant[] = { "BT Info[wifi fw]", @@ -1588,7 +1590,8 @@ static void btc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist) } static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, - u8 wifi_status) { + u8 wifi_status) +{ /* tdma and coex table */ btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); @@ -2412,9 +2415,17 @@ void ex_btc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) void ex_btc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) { struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false; if (btcoexist->manual_control || btcoexist->stop_coex_dm) return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } if (BTC_IPS_ENTER == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -2458,12 +2469,20 @@ void ex_btc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) struct rtl_priv *rtlpriv = btcoexist->adapter; bool wifi_connected = false, bt_hs_on = false; bool bt_ctrl_agg_buf_size = false; + bool wifi_under_5g = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm) return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } if (coex_sta->bt_disabled) return; @@ -2523,11 +2542,19 @@ void ex_btc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; bool bt_ctrl_agg_buf_size = false; + bool wifi_under_5g = false; u8 agg_buf_size = 5; if (btcoexist->manual_control || btcoexist->stop_coex_dm || coex_sta->bt_disabled) return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); @@ -2575,10 +2602,18 @@ void ex_btc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, u8 h2c_parameter[3] = {0}; u32 wifi_bw; u8 wifi_central_chnl; + bool wifi_under_5g = false; if (btcoexist->manual_control || btcoexist->stop_coex_dm || coex_sta->bt_disabled) return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } if (BTC_MEDIA_CONNECT == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -2622,6 +2657,7 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, struct rtl_priv *rtlpriv = btcoexist->adapter; bool bt_hs_on = false; bool bt_ctrl_agg_buf_size = false; + bool wifi_under_5g = false; u32 wifi_link_status = 0; u32 num_of_wifi_link = 0; u8 agg_buf_size = 5; @@ -2630,6 +2666,14 @@ void ex_btc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, coex_sta->bt_disabled) return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } + coex_sta->special_pkt_period_cnt = 0; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, @@ -2818,9 +2862,18 @@ void ex_btc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, void ex_btc8821a1ant_halt_notify(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Halt notify\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } + btcoexist->stop_coex_dm = true; @@ -2836,6 +2889,15 @@ void ex_btc8821a1ant_halt_notify(struct btc_coexist *btcoexist) void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) { struct rtl_priv *rtlpriv = btcoexist->adapter; + bool wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + btc8821a1ant_coex_under_5g(btcoexist); + return; + } RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify\n"); From 4da5e7ea135283ca57be96991d5bca96438c99ad Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 10 Apr 2017 11:23:10 -0500 Subject: [PATCH 094/201] rtlwifi: btcoex: 21a 1ant: avoid LPS/IPS mismatch for pnp notify When driver is going to sleep, it does not leave LPS/IPS, thus the BTCoex may have mismatch when driver wakes up. To avoid that, BTCoex needs to clear the IPS/LPS state when it receives a pnp notify, then it can properly set up the hw when driver wakes up. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a1ant.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 0509ffab9e6ff..5e9f3b0f7a258 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2905,11 +2905,18 @@ void ex_btc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) if (BTC_WIFI_PNP_SLEEP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to SLEEP\n"); + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch + * state after wakeup. + */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; btcoexist->stop_coex_dm = true; - btc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); btc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); - btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); + btc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + btc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + btc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Pnp notify to WAKE UP\n"); From 1f242a3de702d5a19c479685d35b050837122724 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 10 Apr 2017 15:29:45 +0200 Subject: [PATCH 095/201] rt2x00: reverse external PA capability flag logic Consequently refer to external PA instead of inverting the logic and use an internal PA capability flag which is a bit confusing. Currently this is used for Rt3352 only, but MT7620A also allows for an external PA which will be supported by a follow up patch. Signed-off-by: Daniel Golle Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- .../net/wireless/ralink/rt2x00/rt2800lib.c | 40 +++++++++---------- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 4 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 201b12ed90c67..ba06ac2d876da 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -7014,9 +7014,9 @@ static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev) static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) { - int tx0_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX0, + int tx0_ext_pa = test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags); - int tx1_int_pa = test_bit(CAPABILITY_INTERNAL_PA_TX1, + int tx1_ext_pa = test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags); u8 rfcsr; @@ -7056,9 +7056,9 @@ static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 32, 0x80); rt2800_rfcsr_write(rt2x00dev, 33, 0x00); rfcsr = 0x01; - if (!tx0_int_pa) + if (tx0_ext_pa) rt2x00_set_field8(&rfcsr, RFCSR34_TX0_EXT_PA, 1); - if (!tx1_int_pa) + if (tx1_ext_pa) rt2x00_set_field8(&rfcsr, RFCSR34_TX1_EXT_PA, 1); rt2800_rfcsr_write(rt2x00dev, 34, rfcsr); rt2800_rfcsr_write(rt2x00dev, 35, 0x03); @@ -7068,13 +7068,13 @@ static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 39, 0xc5); rt2800_rfcsr_write(rt2x00dev, 40, 0x33); rfcsr = 0x52; - if (tx0_int_pa) { + if (!tx0_ext_pa) { rt2x00_set_field8(&rfcsr, RFCSR41_BIT1, 1); rt2x00_set_field8(&rfcsr, RFCSR41_BIT4, 1); } rt2800_rfcsr_write(rt2x00dev, 41, rfcsr); rfcsr = 0x52; - if (tx1_int_pa) { + if (!tx1_ext_pa) { rt2x00_set_field8(&rfcsr, RFCSR42_BIT1, 1); rt2x00_set_field8(&rfcsr, RFCSR42_BIT4, 1); } @@ -7087,19 +7087,19 @@ static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 48, 0x14); rt2800_rfcsr_write(rt2x00dev, 49, 0x00); rfcsr = 0x2d; - if (!tx0_int_pa) + if (tx0_ext_pa) rt2x00_set_field8(&rfcsr, RFCSR50_TX0_EXT_PA, 1); - if (!tx1_int_pa) + if (tx1_ext_pa) rt2x00_set_field8(&rfcsr, RFCSR50_TX1_EXT_PA, 1); rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); - rt2800_rfcsr_write(rt2x00dev, 51, (tx0_int_pa ? 0x7f : 0x52)); - rt2800_rfcsr_write(rt2x00dev, 52, (tx0_int_pa ? 0x00 : 0xc0)); - rt2800_rfcsr_write(rt2x00dev, 53, (tx0_int_pa ? 0x52 : 0xd2)); - rt2800_rfcsr_write(rt2x00dev, 54, (tx0_int_pa ? 0x1b : 0xc0)); - rt2800_rfcsr_write(rt2x00dev, 55, (tx1_int_pa ? 0x7f : 0x52)); - rt2800_rfcsr_write(rt2x00dev, 56, (tx1_int_pa ? 0x00 : 0xc0)); - rt2800_rfcsr_write(rt2x00dev, 57, (tx0_int_pa ? 0x52 : 0x49)); - rt2800_rfcsr_write(rt2x00dev, 58, (tx1_int_pa ? 0x1b : 0xc0)); + rt2800_rfcsr_write(rt2x00dev, 51, (tx0_ext_pa ? 0x52 : 0x7f)); + rt2800_rfcsr_write(rt2x00dev, 52, (tx0_ext_pa ? 0xc0 : 0x00)); + rt2800_rfcsr_write(rt2x00dev, 53, (tx0_ext_pa ? 0xd2 : 0x52)); + rt2800_rfcsr_write(rt2x00dev, 54, (tx0_ext_pa ? 0xc0 : 0x1b)); + rt2800_rfcsr_write(rt2x00dev, 55, (tx1_ext_pa ? 0x52 : 0x7f)); + rt2800_rfcsr_write(rt2x00dev, 56, (tx1_ext_pa ? 0xc0 : 0x00)); + rt2800_rfcsr_write(rt2x00dev, 57, (tx0_ext_pa ? 0x49 : 0x52)); + rt2800_rfcsr_write(rt2x00dev, 58, (tx1_ext_pa ? 0xc0 : 0x1b)); rt2800_rfcsr_write(rt2x00dev, 59, 0x00); rt2800_rfcsr_write(rt2x00dev, 60, 0x00); rt2800_rfcsr_write(rt2x00dev, 61, 0x00); @@ -8782,13 +8782,13 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rt2x00_rt(rt2x00dev, RT3352)) { - if (!rt2x00_get_field16(eeprom, + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352)) - __set_bit(CAPABILITY_INTERNAL_PA_TX0, + __set_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags); - if (!rt2x00_get_field16(eeprom, + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX1_PA_3352)) - __set_bit(CAPABILITY_INTERNAL_PA_TX1, + __set_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 8fdd2f9726eec..1bc353eafe37d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -719,8 +719,8 @@ enum rt2x00_capability_flags { CAPABILITY_DOUBLE_ANTENNA, CAPABILITY_BT_COEXIST, CAPABILITY_VCO_RECALIBRATION, - CAPABILITY_INTERNAL_PA_TX0, - CAPABILITY_INTERNAL_PA_TX1, + CAPABILITY_EXTERNAL_PA_TX0, + CAPABILITY_EXTERNAL_PA_TX1, }; /* From 26ecfe01790381c4caa65ec9cce484c623f092c4 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 14 Apr 2017 22:27:37 +0100 Subject: [PATCH 096/201] brcmfmac: only build fwsignal module for CONFIG_BRCMFMAC_PROTO_BCDC The fwsignal module is only referenced by the bcdc module and part of the bcdc protocol. So only build it when CONFIG_BRCMFMAC_PROTO_BCDC is selected. Fixes: acf8ac41dd73 ("brcmfmac: remove reference to fwsignal data from struct brcmf_pub") Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index 0383ba559edcc..1f5a9b948abf4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -25,7 +25,6 @@ brcmfmac-objs += \ chip.o \ fwil.o \ fweh.o \ - fwsignal.o \ p2p.o \ proto.o \ common.o \ @@ -36,7 +35,8 @@ brcmfmac-objs += \ vendor.o \ pno.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \ - bcdc.o + bcdc.o \ + fwsignal.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \ commonring.o \ flowring.o \ From b7dcf68f383a05567bd16a390907b67022a62d3d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Apr 2017 08:12:20 +0300 Subject: [PATCH 097/201] ath9k: off by one in ath9k_hw_nvram_read_array() The > should be >= or we read one space beyond the end of the array. Fixes: ab5c4f71d8c7 ("ath9k: allow to load EEPROM content via firmware API") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index fb80ec86e53d0..6ccf248145141 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -112,7 +112,7 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, off_t offset, u16 *data) { - if (offset > blob_size) + if (offset >= blob_size) return false; *data = blob[offset]; From 050fd820dc177a77f6f74a152db22fff25a35032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Th=C3=A9bault?= Date: Thu, 6 Apr 2017 13:51:10 +0200 Subject: [PATCH 098/201] ath9k: Add Dell Wireless 1601 with wowlan capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Dell Wireless 1601 card as an AR9462 in the ath9k pci list. Note that the wowlan feature is supported and has been tested successfully. Signed-off-by: Damien Thébault Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index aff473dfa10df..7b7627f85d3a5 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -383,6 +383,11 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x10CF, /* Fujitsu */ 0x1783), .driver_data = ATH9K_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_DELL, + 0x020B), + .driver_data = ATH9K_PCI_WOW }, /* Killer Wireless (2x2) */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, From 627871b71c89a6ec12fbed75063f238e0c7127b2 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 6 Apr 2017 14:21:35 -0700 Subject: [PATCH 099/201] ath9k: Add cast to u8 to FREQ2FBIN macro The macro results are assigned to u8 variables/fields. Adding the cast fixes plenty of clang warnings about "implicit conversion from 'int' to 'u8'". Signed-off-by: Matthias Kaehlcke Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 30bf722e33ede..31390af6c33e3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -106,7 +106,7 @@ #define AR9285_RDEXT_DEFAULT 0x1F #define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) -#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define FREQ2FBIN(x, y) (u8)((y) ? ((x) - 2300) : (((x) - 4800) / 5)) #define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x)) #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) From a4aab099cc9e7c4c94b8a0973b2a483c69b541e3 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 10 Apr 2017 21:08:17 +0530 Subject: [PATCH 100/201] ath10k: fix spectral scan for QCA99X0 family of chipsets spectral_bin length (number of bins per fft sample) is usually a value where (2^n = value), n is an integer. All of the QCA99X0 family of chipsets seems to report a spectral_bin length of 2^n + 'm' bytes, where m = 4, 12 based on the chipset. This 'm' bytes seems to carry some radar related info which is currently discarded only for 'bin_len = 68' bytes. Extend this discarding of irrelevant 'bin_len' for QCA9984, QCA9888, IPQ4019 as well by introducing a hardware parameter 'spectral_bin_discard'. Also for QCA988X based family of chipsets which doesn't seem to have this issue and also for some of the hardware which I have not tested like QCA6174/QCA9377 the existing behaviour is retained as it is. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 12 ++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 3 +++ drivers/net/wireless/ath/ath10k/spectral.c | 26 ++++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 1b4c08b5eaa9d..5a06389158744 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -71,6 +71,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA9887_HW_1_0_VERSION, @@ -91,6 +92,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -110,6 +112,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA6174_HW_2_1_VERSION, @@ -129,6 +132,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA6174_HW_3_0_VERSION, @@ -148,6 +152,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA6174_HW_3_2_VERSION, @@ -170,6 +175,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_clk = qca6174_clk, .target_cpu_freq = 176000000, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, @@ -195,6 +201,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, + .spectral_bin_discard = 4, }, { .id = QCA9984_HW_1_0_DEV_VERSION, @@ -221,6 +228,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, + .spectral_bin_discard = 12, }, { .id = QCA9888_HW_2_0_DEV_VERSION, @@ -246,6 +254,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, + .spectral_bin_discard = 12, }, { .id = QCA9377_HW_1_0_DEV_VERSION, @@ -265,6 +274,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, .hw_ops = &qca988x_ops, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA9377_HW_1_1_DEV_VERSION, @@ -286,6 +296,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .hw_clk = qca6174_clk, .target_cpu_freq = 176000000, .decap_align_bytes = 4, + .spectral_bin_discard = 0, }, { .id = QCA4019_HW_1_0_DEV_VERSION, @@ -312,6 +323,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, .decap_align_bytes = 1, + .spectral_bin_discard = 4, }, }; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 8aca62bca3487..fd432b60dca76 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -448,6 +448,9 @@ struct ath10k_hw_params { /* hw specific clock control parameters */ const struct ath10k_hw_clk_params *hw_clk; int target_cpu_freq; + + /* Number of bytes to be discarded for each FFT sample */ + int spectral_bin_discard; }; struct htt_rx_desc; diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 46471ed302752..dd9cc0939ea81 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -56,6 +56,21 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len, return max_exp; } +static inline size_t ath10k_spectral_fix_bin_size(struct ath10k *ar, + size_t bin_len) +{ + /* some chipsets reports bin size as 2^n bytes + 'm' bytes in + * report mode 2. First 2^n bytes carries inband tones and last + * 'm' bytes carries band edge detection data mainly used in + * radar detection purpose. Strip last 'm' bytes to make bin size + * as a valid one. 'm' can take possible values of 4, 12. + */ + if (!is_power_of_2(bin_len)) + bin_len -= ar->hw_params.spectral_bin_discard; + + return bin_len; +} + int ath10k_spectral_process_fft(struct ath10k *ar, struct wmi_phyerr_ev_arg *phyerr, const struct phyerr_fft_report *fftr, @@ -70,18 +85,11 @@ int ath10k_spectral_process_fft(struct ath10k *ar, fft_sample = (struct fft_sample_ath10k *)&buf; + bin_len = ath10k_spectral_fix_bin_size(ar, bin_len); + if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS) return -EINVAL; - /* qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in - * report mode 2. First 64 bytes carries inband tones (-32 to +31) - * and last 4 byte carries band edge detection data (+32) mainly - * used in radar detection purpose. Strip last 4 byte to make bin - * size is valid one. - */ - if (bin_len == 68) - bin_len -= 4; - reg0 = __le32_to_cpu(fftr->reg0); reg1 = __le32_to_cpu(fftr->reg1); From aad1fd7f7677d05013b5fe247a5a6e1464c69a0f Mon Sep 17 00:00:00 2001 From: Ryan Hsu Date: Tue, 11 Apr 2017 14:04:48 -0700 Subject: [PATCH 101/201] ath10k: bump up FW API to 6 For QCA6174 hw3.0, since WLAN.RM.4.4-00022-QCARMSWPZ-2, it starts to support the board ID information from otp, with some devices released on the market that didn't calibrated with OTP, will have 0 for board ID information, which cause the backward compatibility issue and was fixed in commit 'd2e202c06ca4 ("ath10k: ignore configuring the incorrect board_id")' So bump the fw api version to differentiate the latest firmware support. Signed-off-by: Ryan Hsu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 5 ++++- drivers/net/wireless/ath/ath10k/pci.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index fd432b60dca76..5b1e90bb2a4db 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -129,7 +129,7 @@ enum qca9377_chip_id_rev { #define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234 #define ATH10K_FW_FILE_BASE "firmware" -#define ATH10K_FW_API_MAX 5 +#define ATH10K_FW_API_MAX 6 #define ATH10K_FW_API_MIN 2 #define ATH10K_FW_API2_FILE "firmware-2.bin" @@ -141,6 +141,9 @@ enum qca9377_chip_id_rev { /* HTT id conflict fix for management frames over HTT */ #define ATH10K_FW_API5_FILE "firmware-5.bin" +/* the firmware-6.bin blob */ +#define ATH10K_FW_API6_FILE "firmware-6.bin" + #define ATH10K_FW_UTF_FILE "utf.bin" #define ATH10K_FW_UTF_API2_FILE "utf-2.bin" diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index b20b66d9d7bcf..1e9806f57ee41 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3428,6 +3428,7 @@ MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA6174 3.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); +MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); From b90189759a7ff92aa47e8878f6b5a9f868e19895 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 23 Mar 2017 14:30:48 +0100 Subject: [PATCH 102/201] ath9k: add noise floor override option Introduce a debugfs option to manually override the noise floor, ignoring the automatically tuned noise floor of the driver/hw. In my tests with a AR9580 based module and a tx99 5 MHz interferer, I could tune the noisefloor to -95 dBm or above to allow communication again. The automatic noise floor calibration sometimes could adapt to the situation as well, but not reliably and permanently. I would consider this "feature" experimental and interesting for people debugging the noise floor calibration or other effects of the hardware. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/calib.c | 5 ++- drivers/net/wireless/ath/ath9k/debug.c | 62 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 0f71146b781d1..13ab6bc467753 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -254,7 +254,9 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan)) continue; - if (h) + if (ah->nf_override) + nfval = ah->nf_override; + else if (h) nfval = h[i].privNF; else nfval = default_nf; @@ -348,6 +350,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) return 0; } +EXPORT_SYMBOL(ath9k_hw_loadnf); static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 43930c336987e..2e64977a8ab66 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1191,6 +1191,65 @@ static const struct file_operations fops_tpc = { .llseek = default_llseek, }; +static ssize_t read_file_nf_override(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + char buf[32]; + unsigned int len; + + if (ah->nf_override == 0) + len = sprintf(buf, "off\n"); + else + len = sprintf(buf, "%d\n", ah->nf_override); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_nf_override(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strncmp("off", buf, 3) == 0) + val = 0; + else if (kstrtol(buf, 0, &val)) + return -EINVAL; + + if (val > 0) + return -EINVAL; + + if (val < -120) + return -EINVAL; + + ah->nf_override = val; + + if (ah->curchan) + ath9k_hw_loadnf(ah, ah->curchan); + + return count; +} + +static const struct file_operations fops_nf_override = { + .read = read_file_nf_override, + .write = write_file_nf_override, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1402,5 +1461,8 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_u16("airtime_flags", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->airtime_flags); + debugfs_create_file("nf_override", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_nf_override); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9cbca1229bac0..4ac70827d142c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -803,6 +803,7 @@ struct ath_hw { u32 rfkill_gpio; u32 rfkill_polarity; u32 ah_flags; + s16 nf_override; bool reset_power_on; bool htc_reset_init; From c0c345d4cacc6a1f39d4856f37dcf6e34f51a5e4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 12 Apr 2017 23:19:37 +0530 Subject: [PATCH 103/201] ath: Fix updating radar flags for coutry code India As per latest regulatory update for India, channel 52, 56, 60, 64 is no longer restricted to DFS. Enabling DFS/no infra flags in driver results in applying all DFS related restrictions (like doing CAC etc before this channel moves to 'available state') for these channels even though the country code is programmed as 'India' in he hardware, fix this by relaxing the frequency range while applying RADAR flags only if the country code is programmed to India. If the frequency range needs to modified based on different country code, ath_is_radar_freq can be extended/modified dynamically. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 43afa83a9f0c1..e25bfdf78c2e1 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -254,8 +254,12 @@ bool ath_is_49ghz_allowed(u16 regdomain) EXPORT_SYMBOL(ath_is_49ghz_allowed); /* Frequency is one where radar detection is required */ -static bool ath_is_radar_freq(u16 center_freq) +static bool ath_is_radar_freq(u16 center_freq, + struct ath_regulatory *reg) + { + if (reg->country_code == CTRY_INDIA) + return (center_freq >= 5500 && center_freq <= 5700); return (center_freq >= 5260 && center_freq <= 5700); } @@ -306,7 +310,7 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ieee80211_channel *ch) { - if (ath_is_radar_freq(ch->center_freq) || + if (ath_is_radar_freq(ch->center_freq, reg) || (ch->flags & IEEE80211_CHAN_RADAR)) return; @@ -395,8 +399,9 @@ ath_reg_apply_ir_flags(struct wiphy *wiphy, } } -/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -static void ath_reg_apply_radar_flags(struct wiphy *wiphy) +/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ +static void ath_reg_apply_radar_flags(struct wiphy *wiphy, + struct ath_regulatory *reg) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -409,7 +414,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; - if (!ath_is_radar_freq(ch->center_freq)) + if (!ath_is_radar_freq(ch->center_freq, reg)) continue; /* We always enable radar detection/DFS on this * frequency range. Additionally we also apply on @@ -506,7 +511,7 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, struct ath_common *common = container_of(reg, struct ath_common, regulatory); /* We always apply this */ - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); /* * This would happen when we have sent a custom regulatory request @@ -654,7 +659,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, } wiphy_apply_custom_regulatory(wiphy, regd); - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); return 0; } From d6be9c1d0b2e9b1d4722de2d6e5dabeff56c88a5 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 12 Jan 2017 11:31:25 +0200 Subject: [PATCH 104/201] iwlwifi: mvm: read new secure boot registers Addresses were changed for a000 devices. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index bb7e0d642981d..e1aa1f7836fc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -400,6 +400,8 @@ enum aux_misc_master1_en { #define PREG_AUX_BUS_WPROT_0 0xA04CC0 #define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_2_STATUS 0xA01E34 +#define UMAG_SB_CPU_1_STATUS 0xA038C0 +#define UMAG_SB_CPU_2_STATUS 0xA038C4 /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e481bb050c6e7..6adbd4bcb40a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -639,11 +639,18 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, MVM_UCODE_ALIVE_TIMEOUT); if (ret) { - if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + struct iwl_trans *trans = mvm->trans; + + if (trans->cfg->gen2) + IWL_ERR(mvm, + "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", + iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS), + iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS)); + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_prph(mvm->trans, SB_CPU_1_STATUS), - iwl_read_prph(mvm->trans, SB_CPU_2_STATUS)); + iwl_read_prph(trans, SB_CPU_1_STATUS), + iwl_read_prph(trans, SB_CPU_2_STATUS)); mvm->cur_ucode = old_type; return ret; } From c5a719ee575ccace15eb9ad49c13c2750946c303 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 15 Nov 2016 10:20:48 +0200 Subject: [PATCH 105/201] iwlwifi: mvm: add queues after adding station Currently aux & broadcast queues are added before calling add station, which results with a SCD_QUEUE_CFG command sent with a station id unknown yet to fw. While this works for pre-a000 firmware, the a000 fw requires the order to be reversed. The reason the change is only for a000 devices and not for previous devices is that we cannot reverse the order since the tfd_queue_mask containing the aux queue will cause FW to assert on adding a queue mask with a queue that is not enabled. This is not a problem in a000 fw since the tfd_queue_mask was removed from the add sta API. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index a552955f72f72..566d57ec86ce4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1700,25 +1700,11 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) +static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) { unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? mvm->cfg->base_params->wd_timeout : IWL_WATCHDOG_DISABLED; - int ret; - - lockdep_assert_held(&mvm->mutex); - - /* Map Aux queue to fifo - needs to happen before adding Aux station */ - if (!iwl_mvm_is_dqa_supported(mvm)) - iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); - - /* Allocate aux station and assign to it the aux queue */ - ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), - NL80211_IFTYPE_UNSPECIFIED); - if (ret) - return ret; if (iwl_mvm_is_dqa_supported(mvm)) { struct iwl_trans_txq_scd_cfg cfg = { @@ -1731,14 +1717,43 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg, wdg_timeout); + } else { + iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, + IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); } +} - ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, - MAC_INDEX_AUX, 0); +int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) +{ + int ret; + + lockdep_assert_held(&mvm->mutex); + /* Allocate aux station and assign to it the aux queue */ + ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), + NL80211_IFTYPE_UNSPECIFIED); if (ret) + return ret; + + /* Map Aux queue to fifo - needs to happen before adding Aux station */ + if (!iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_aux_queue(mvm); + + ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL, + MAC_INDEX_AUX, 0); + if (ret) { iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta); - return ret; + return ret; + } + + /* + * For a000 firmware and on we cannot add queue to a station unknown + * to firmware so enable queue here - after the station was added + */ + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_aux_queue(mvm); + + return 0; } int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -1789,22 +1804,21 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const u8 *baddr = _baddr; + int queue = 0; int ret; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = IWL_MVM_TX_FIFO_VO, + .sta_id = mvmvif->bcast_sta.sta_id, + .tid = IWL_MAX_TID_COUNT, + .aggregate = false, + .frame_limit = IWL_FRAME_LIMIT, + }; lockdep_assert_held(&mvm->mutex); if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = IWL_MVM_TX_FIFO_VO, - .sta_id = mvmvif->bcast_sta.sta_id, - .tid = IWL_MAX_TID_COUNT, - .aggregate = false, - .frame_limit = IWL_FRAME_LIMIT, - }; - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, vif, false, false); - int queue; - if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) queue = mvm->probe_queue; @@ -1813,9 +1827,11 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) else if (WARN(1, "Missing required TXQ for adding bcast STA\n")) return -EINVAL; - iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, &cfg, - wdg_timeout); bsta->tfd_queue_msk |= BIT(queue); + + if (!iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, + &cfg, wdg_timeout); } if (vif->type == NL80211_IFTYPE_ADHOC) @@ -1830,28 +1846,12 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; /* - * In AP vif type, we also need to enable the cab_queue. However, we - * have to enable it after the ADD_STA command is sent, otherwise the - * FW will throw an assert once we send the ADD_STA command (it'll - * detect a mismatch in the tfd_queue_msk, as we can't add the - * enabled-cab_queue to the mask) + * For a000 firmware and on we cannot add queue to a station unknown + * to firmware so enable queue here - after the station was added */ - if (iwl_mvm_is_dqa_supported(mvm) && - (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC)) { - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = IWL_MVM_TX_FIFO_MCAST, - .sta_id = mvmvif->bcast_sta.sta_id, - .tid = IWL_MAX_TID_COUNT, - .aggregate = false, - .frame_limit = IWL_FRAME_LIMIT, - }; - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, vif, false, false); - - iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, - 0, &cfg, wdg_timeout); - } + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, &cfg, + wdg_timeout); return 0; } From dd48847763a79f0382e0383c85bbe01f3cd57a10 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 15 Jan 2017 17:08:40 +0200 Subject: [PATCH 106/201] iwlwifi: cleanup unused function iwl_has_secure_boot() isn't getting called anywhere. Clean it up. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 717e089ff036f..06034a71a1905 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -90,16 +90,6 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_8000, }; -static inline bool iwl_has_secure_boot(u32 hw_rev, - enum iwl_device_family family) -{ - /* return 1 only for family 8000 B0 */ - if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC)) - return true; - - return false; -} - /* * LED mode * IWL_LED_DEFAULT: use device default From 0ae988125d777ce5b564cf73e6d83c471e32aff9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 4 Jan 2017 14:53:58 +0200 Subject: [PATCH 107/201] iwlwifi: mvm: prepare for station count change In a000 devices we will support up to 32 stations. The max station define is used also for invalid station marking which makes finding usages of actual maximum station pretty hard to sort through - change it to be a different define in order to make future changes easier. Use also ARRAY_SIZE intead of define when possible. Do not move yet to 32 stations until firmware do it though. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../wireless/intel/iwlwifi/mvm/debugfs-vif.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- .../wireless/intel/iwlwifi/mvm/fw-api-mac.h | 4 ++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 6 ++-- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 6 ++-- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 12 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 6 ++-- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 30 +++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 22 +++++++------- drivers/net/wireless/intel/iwlwifi/mvm/tof.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 6 ++-- .../net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- 18 files changed, 66 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 5bdb6c2c8390b..49b4418e6c35d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -756,7 +756,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Rssi update while not associated - can happen since the statistics * are handled asynchronously */ - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) + if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) return; /* No BT - reports should be disabled */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d65acfa3b89b9..d74ae15b2d856 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1208,7 +1208,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) { + if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index f4d75ffe3d8a8..5d475b4850ae3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -280,7 +280,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->queue_params[i].uapsd); if (vif->type == NL80211_IFTYPE_STATION && - ap_sta_id != IWL_MVM_STATION_COUNT) { + ap_sta_id != IWL_MVM_INVALID_STA) { struct iwl_mvm_sta *mvm_sta; mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 077bfd8f4c0cd..402846650cbec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -330,7 +330,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, mutex_lock(&mvm->mutex); - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 480a54af45347..d3cdd889c85c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -73,7 +73,9 @@ #define NUM_MAC_INDEX (NUM_MAC_INDEX_DRIVER + 1) #define NUM_MAC_INDEX_CDB (NUM_MAC_INDEX_DRIVER + 2) -#define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_INVALID_STA 0xFF + #define IWL_MVM_TDLS_STA_COUNT 4 enum iwl_ac { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6adbd4bcb40a3..61cafb5415548 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1250,10 +1250,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) } /* init the fw <-> mac80211 STA mapping */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); - mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; + mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; /* reset quota debouncing buffer - 0xff will yield invalid data */ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); @@ -1383,7 +1383,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) goto error; /* init the fw <-> mac80211 STA mapping */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); /* Add auxiliary station for scanning */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 626864f3701c0..ae1406fe99889 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -472,9 +472,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; } - mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; - mvmvif->mcast_sta.sta_id = IWL_MVM_STATION_COUNT; - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + mvmvif->bcast_sta.sta_id = IWL_MVM_INVALID_STA; + mvmvif->mcast_sta.sta_id = IWL_MVM_INVALID_STA; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) mvmvif->smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index afe0e0f0744fc..26cf3dfcc108e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -767,7 +767,7 @@ static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, goto out; mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (mvmsta->sta_id == IWL_MVM_STATION_COUNT || + if (mvmsta->sta_id == IWL_MVM_INVALID_STA || mvmsta->sta_id != mvm->d0i3_ap_sta_id) goto out; @@ -1011,7 +1011,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->uploaded = false; - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); @@ -1054,7 +1054,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm); mvm->p2p_device_vif = NULL; - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); @@ -1965,7 +1965,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_MVM_SMPS_REQ_PROT, IEEE80211_SMPS_DYNAMIC); } - } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { + } else if (mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { /* * If update fails - SF might be running in associated * mode while disassociated - which is forbidden. @@ -1979,8 +1979,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_ERR(mvm, "failed to remove AP station\n"); if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; /* remove quota for this interface */ ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) @@ -2391,7 +2391,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, */ break; case STA_NOTIFY_AWAKE: - if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON(mvmsta->sta_id == IWL_MVM_INVALID_STA)) break; if (txqs) @@ -3961,7 +3961,7 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); /* flush the AP-station and all TDLS peers */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(sta)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 72afccfe42827..d313941ffc9d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1268,7 +1268,7 @@ static bool iwl_mvm_disallow_offloading(struct iwl_mvm *mvm, u8 tid; if (WARN_ON(vif->type != NL80211_IFTYPE_STATION || - mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)) + mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)) return false; mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id); @@ -1356,7 +1356,7 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, struct ieee80211_sta *ap_sta; struct iwl_mvm_sta *mvm_ap_sta; - if (iter_data->ap_sta_id == IWL_MVM_STATION_COUNT) + if (iter_data->ap_sta_id == IWL_MVM_INVALID_STA) return; rcu_read_lock(); @@ -1426,7 +1426,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) mvm->d0i3_offloading = !d0i3_iter_data.disable_offloading; } else { WARN_ON_ONCE(d0i3_iter_data.vif_count > 1); - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; mvm->d0i3_offloading = false; } @@ -1439,7 +1439,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) return ret; /* configure wowlan configuration only if needed */ - if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) { + if (mvm->d0i3_ap_sta_id != IWL_MVM_INVALID_STA) { /* wake on beacons only if beacon storing isn't supported */ if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEACON_STORING)) @@ -1516,7 +1516,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) spin_lock_bh(&mvm->d0i3_tx_lock); - if (mvm->d0i3_ap_sta_id == IWL_MVM_STATION_COUNT) + if (mvm->d0i3_ap_sta_id == IWL_MVM_INVALID_STA) goto out; IWL_DEBUG_RPM(mvm, "re-enqueue packets\n"); @@ -1554,7 +1554,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) } clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); wake_up(&mvm->d0i3_exit_waitq); - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; if (wake_queues) ieee80211_wake_queues(mvm->hw); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index c1bf67f04cf60..861d54641d1e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -351,7 +351,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT; - if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) { + if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) { sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); if (IS_ERR(sta)) sta = NULL; @@ -693,7 +693,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, } rcu_read_lock(); - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { struct iwl_mvm_sta *sta; if (!energy[i]) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 85f7c83995b95..29c9c56ed3fa3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -841,7 +841,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) { u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; - if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) { + if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) { sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); if (IS_ERR(sta)) sta = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 101fb04a85734..539b06bf08031 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -235,7 +235,7 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); break; case SF_FULL_ON: - if (sta_id == IWL_MVM_STATION_COUNT) { + if (sta_id == IWL_MVM_INVALID_STA) { IWL_ERR(mvm, "No station: Cannot switch SF to FULL_ON\n"); return -EINVAL; @@ -276,12 +276,12 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, bool remove_vif) { enum iwl_sf_state new_state; - u8 sta_id = IWL_MVM_STATION_COUNT; + u8 sta_id = IWL_MVM_INVALID_STA; struct iwl_mvm_vif *mvmvif = NULL; struct iwl_mvm_active_iface_iterator_data data = { .ignore_vif = changed_vif, .sta_vif_state = SF_UNINIT, - .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT, + .sta_vif_ap_sta_id = IWL_MVM_INVALID_STA, }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 566d57ec86ce4..fb031197266ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -98,7 +98,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, reserved_ids = BIT(0); /* Don't take rcu_read_lock() since we are protected by mvm->mutex */ - for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) { + for (sta_id = 0; sta_id < ARRAY_SIZE(mvm->fw_id_to_mac_id); sta_id++) { if (BIT(sta_id) & reserved_ids) continue; @@ -106,7 +106,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, lockdep_is_held(&mvm->mutex))) return sta_id; } - return IWL_MVM_STATION_COUNT; + return IWL_MVM_INVALID_STA; } /* send station add/update command to firmware */ @@ -1235,7 +1235,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, else sta_id = mvm_sta->sta_id; - if (sta_id == IWL_MVM_STATION_COUNT) + if (sta_id == IWL_MVM_INVALID_STA) return -ENOSPC; spin_lock_init(&mvm_sta->lock); @@ -1317,10 +1317,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION) { if (!sta->tdls) { - WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT); + WARN_ON(mvmvif->ap_sta_id != IWL_MVM_INVALID_STA); mvmvif->ap_sta_id = sta_id; } else { - WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT); + WARN_ON(mvmvif->ap_sta_id == IWL_MVM_INVALID_STA); } } @@ -1571,11 +1571,11 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, return ret; /* unassoc - go ahead - remove the AP STA now */ - mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; /* clear d0i3_ap_sta_id if no longer relevant */ if (mvm->d0i3_ap_sta_id == sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; } } @@ -1584,7 +1584,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, * before the STA is removed. */ if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) { - mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; + mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; cancel_delayed_work(&mvm->tdls_cs.dwork); } @@ -1641,7 +1641,7 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) return -ENOSPC; } @@ -1656,7 +1656,7 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); - sta->sta_id = IWL_MVM_STATION_COUNT; + sta->sta_id = IWL_MVM_INVALID_STA; } static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, @@ -1837,7 +1837,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_ADHOC) baddr = vif->bss_conf.bssid; - if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_INVALID_STA)) return -ENOSPC; ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, @@ -2742,7 +2742,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, * station ID, then use AP's station ID. */ if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { + mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { u8 sta_id = mvmvif->ap_sta_id; sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], @@ -2954,7 +2954,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, return sta->addr; if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { + mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { u8 sta_id = mvmvif->ap_sta_id; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); @@ -3151,7 +3151,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id = IWL_MVM_STATION_COUNT; + u8 sta_id = IWL_MVM_INVALID_STA; int ret, i; lockdep_assert_held(&mvm->mutex); @@ -3408,7 +3408,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); /* Block/unblock all the stations of the given mvmvif */ - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(sta)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 9f160fc58cd07..df7cd87199ea2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -78,7 +80,7 @@ void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); if (!sta || IS_ERR(sta) || !sta->tdls) @@ -101,7 +103,7 @@ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); if (!sta || IS_ERR(sta) || !sta->tdls) @@ -145,7 +147,7 @@ static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* populate TDLS peer data */ cnt = 0; - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(sta) || !sta->tdls) @@ -251,7 +253,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); if (state == IWL_MVM_TDLS_SW_IDLE) - mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; + mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA; } void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) @@ -305,7 +307,7 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, /* get the existing peer if it's there */ if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && - mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { + mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { struct ieee80211_sta *sta = rcu_dereference_protected( mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], lockdep_is_held(&mvm->mutex)); @@ -523,7 +525,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); /* station might be gone, in that case do nothing */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) + if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) goto out; sta = rcu_dereference_protected( @@ -573,7 +575,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, sta->addr, chandef->chan->center_freq, chandef->width); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id != IWL_MVM_STATION_COUNT) { + if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "Existing peer. Can't start switch with %pM\n", sta->addr); @@ -633,7 +635,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_STATION_COUNT) { + if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr); goto out; } @@ -654,7 +656,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE) wait_for_phy = true; - mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; + mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; dev_kfree_skb(mvm->tdls_cs.peer.skb); mvm->tdls_cs.peer.skb = NULL; @@ -697,7 +699,7 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE && params->status != 0 && mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && - mvm->tdls_cs.cur_sta_id != IWL_MVM_STATION_COUNT) { + mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { struct ieee80211_sta *cur_sta; /* make sure it's the same peer */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index a1947d6f3a2cc..16ce8a56b5b94 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -80,7 +80,7 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm) if (IWL_MVM_TOF_IS_RESPONDER) { tof_data->responder_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); - tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; + tof_data->responder_cfg.sta_id = IWL_MVM_INVALID_STA; } #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index bec7d9c46087d..f9cbd197246f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -356,7 +356,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) struct iwl_mvm_sta *mvmsta; int i, err; - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i); if (!mvmsta) continue; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ffbbe7228f5d4..00b6eaca08925 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -598,7 +598,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) is_multicast_ether_addr(hdr->addr1)) { u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); - if (ap_sta_id != IWL_MVM_STATION_COUNT) + if (ap_sta_id != IWL_MVM_INVALID_STA) sta_id = ap_sta_id; } else if (iwl_mvm_is_dqa_supported(mvm) && info.control.vif->type == NL80211_IFTYPE_STATION && @@ -896,7 +896,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(!mvmsta)) return -1; - if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA)) return -1; dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen, @@ -1036,7 +1036,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(!mvmsta)) return -1; - if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA)) return -1; memcpy(&info, skb->cb, sizeof(info)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8f199ff9be870..3054945b949ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -824,7 +824,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init) .data = { lq, }, }; - if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT)) + if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA)) return -EINVAL; return iwl_mvm_send_cmd(mvm, &cmd); From a0b4828c20ce9ab34e6ae8be0148eb55e6a89193 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 12 Jan 2017 16:01:11 +0200 Subject: [PATCH 108/201] iwlwifi: mvm: use same scan API for all a000 devices API will be the same regardless of FW compilation. CDB related values will be filled in only for CDB. Cahneg code and names accordingly. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/fw-api-scan.h | 14 ++-- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 80 ++++++++++--------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h index c78a0c4994598..3178eb96e3950 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h @@ -516,7 +516,7 @@ struct iwl_scan_dwell { * scan_config_channel_flag * @channel_array: default supported channels */ -struct iwl_scan_config { +struct iwl_scan_config_v1 { __le32 flags; __le32 tx_chains; __le32 rx_chains; @@ -532,7 +532,7 @@ struct iwl_scan_config { #define SCAN_TWO_LMACS 2 -struct iwl_scan_config_cdb { +struct iwl_scan_config { __le32 flags; __le32 tx_chains; __le32 rx_chains; @@ -669,7 +669,7 @@ struct iwl_scan_req_umac { u8 n_channels; __le16 reserved; u8 data[]; - } no_cdb; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ + } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ struct { __le32 max_out_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; @@ -679,13 +679,13 @@ struct iwl_scan_req_umac { u8 n_channels; __le16 reserved; u8 data[]; - } cdb; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_5 */ + } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */ }; } __packed; -#define IWL_SCAN_REQ_UMAC_SIZE_CDB sizeof(struct iwl_scan_req_umac) -#define IWL_SCAN_REQ_UMAC_SIZE (sizeof(struct iwl_scan_req_umac) - \ - 2 * sizeof(__le32)) +#define IWL_SCAN_REQ_UMAC_SIZE sizeof(struct iwl_scan_req_umac) +#define IWL_SCAN_REQ_UMAC_SIZE_V1 (sizeof(struct iwl_scan_req_umac) - \ + 2 * sizeof(__le32)) /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 0a64efa844b75..ce6a2b3b021e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -966,11 +966,11 @@ static void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels) channels[j] = band->channels[i].hw_value; } -static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, - u32 flags, u8 channel_flags) +static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, + u32 flags, u8 channel_flags) { enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); - struct iwl_scan_config *cfg = config; + struct iwl_scan_config_v1 *cfg = config; cfg->flags = cpu_to_le32(flags); cfg->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); @@ -989,11 +989,11 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, iwl_mvm_fill_channels(mvm, cfg->channel_array); } -static void iwl_mvm_fill_scan_config_cdb(struct iwl_mvm *mvm, void *config, - u32 flags, u8 channel_flags) +static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, + u32 flags, u8 channel_flags) { enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false); - struct iwl_scan_config_cdb *cfg = config; + struct iwl_scan_config *cfg = config; cfg->flags = cpu_to_le32(flags); cfg->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); @@ -1001,10 +1001,14 @@ static void iwl_mvm_fill_scan_config_cdb(struct iwl_mvm *mvm, void *config, cfg->legacy_rates = iwl_mvm_scan_config_rates(mvm); cfg->out_of_channel_time[0] = cpu_to_le32(scan_timing[type].max_out_time); - cfg->out_of_channel_time[1] = - cpu_to_le32(scan_timing[type].max_out_time); cfg->suspend_time[0] = cpu_to_le32(scan_timing[type].suspend_time); - cfg->suspend_time[1] = cpu_to_le32(scan_timing[type].suspend_time); + + if (iwl_mvm_is_cdb_supported(mvm)) { + cfg->suspend_time[1] = + cpu_to_le32(scan_timing[type].suspend_time); + cfg->out_of_channel_time[1] = + cpu_to_le32(scan_timing[type].max_out_time); + } iwl_mvm_fill_scan_dwell(mvm, &cfg->dwell, &scan_timing[type]); @@ -1039,10 +1043,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) return 0; } - if (iwl_mvm_is_cdb_supported(mvm)) - cmd_size = sizeof(struct iwl_scan_config_cdb); - else + if (iwl_mvm_has_new_tx_api(mvm)) cmd_size = sizeof(struct iwl_scan_config); + else + cmd_size = sizeof(struct iwl_scan_config_v1); cmd_size += mvm->fw->ucode_capa.n_scan_channels; cfg = kzalloc(cmd_size, GFP_KERNEL); @@ -1068,13 +1072,13 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) IWL_CHANNEL_FLAG_EBS_ADD | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; - if (iwl_mvm_is_cdb_supported(mvm)) { + if (iwl_mvm_has_new_tx_api(mvm)) { flags |= (type == IWL_SCAN_TYPE_FRAGMENTED) ? SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; - iwl_mvm_fill_scan_config_cdb(mvm, cfg, flags, channel_flags); - } else { iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags); + } else { + iwl_mvm_fill_scan_config_v1(mvm, cfg, flags, channel_flags); } cmd.data[0] = cfg; @@ -1119,16 +1123,20 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, } cmd->fragmented_dwell = timing->dwell_fragmented; - if (iwl_mvm_is_cdb_supported(mvm)) { - cmd->cdb.max_out_time[0] = cpu_to_le32(timing->max_out_time); - cmd->cdb.suspend_time[0] = cpu_to_le32(timing->suspend_time); - cmd->cdb.max_out_time[1] = cpu_to_le32(timing->max_out_time); - cmd->cdb.suspend_time[1] = cpu_to_le32(timing->suspend_time); - cmd->cdb.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + if (iwl_mvm_has_new_tx_api(mvm)) { + cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->v6.max_out_time[0] = cpu_to_le32(timing->max_out_time); + cmd->v6.suspend_time[0] = cpu_to_le32(timing->suspend_time); + if (iwl_mvm_is_cdb_supported(mvm)) { + cmd->v6.max_out_time[1] = + cpu_to_le32(timing->max_out_time); + cmd->v6.suspend_time[1] = + cpu_to_le32(timing->suspend_time); + } } else { - cmd->no_cdb.max_out_time = cpu_to_le32(timing->max_out_time); - cmd->no_cdb.suspend_time = cpu_to_le32(timing->suspend_time); - cmd->no_cdb.scan_priority = + cmd->v1.max_out_time = cpu_to_le32(timing->max_out_time); + cmd->v1.suspend_time = cpu_to_le32(timing->suspend_time); + cmd->v1.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); } @@ -1207,8 +1215,8 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int type) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; - void *cmd_data = iwl_mvm_is_cdb_supported(mvm) ? - (void *)&cmd->cdb.data : (void *)&cmd->no_cdb.data; + void *cmd_data = iwl_mvm_has_new_tx_api(mvm) ? + (void *)&cmd->v6.data : (void *)&cmd->v1.data; struct iwl_scan_req_umac_tail *sec_part = cmd_data + sizeof(struct iwl_scan_channel_cfg_umac) * mvm->fw->ucode_capa.n_scan_channels; @@ -1245,12 +1253,12 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; - if (iwl_mvm_is_cdb_supported(mvm)) { - cmd->cdb.channel_flags = channel_flags; - cmd->cdb.n_channels = params->n_channels; + if (iwl_mvm_has_new_tx_api(mvm)) { + cmd->v6.channel_flags = channel_flags; + cmd->v6.n_channels = params->n_channels; } else { - cmd->no_cdb.channel_flags = channel_flags; - cmd->no_cdb.n_channels = params->n_channels; + cmd->v1.channel_flags = channel_flags; + cmd->v1.n_channels = params->n_channels; } iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap); @@ -1692,10 +1700,10 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) int iwl_mvm_scan_size(struct iwl_mvm *mvm) { - int base_size = IWL_SCAN_REQ_UMAC_SIZE; + int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; - if (iwl_mvm_is_cdb_supported(mvm)) - base_size = IWL_SCAN_REQ_UMAC_SIZE_CDB; + if (iwl_mvm_has_new_tx_api(mvm)) + base_size = IWL_SCAN_REQ_UMAC_SIZE; if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) return base_size + From 09a2e25d10cd85d981fb19fdcf1bc460f1706e22 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 19 Dec 2016 14:10:35 +0200 Subject: [PATCH 109/201] iwlwifi: mvm: disable multi-queue for a000 devices Firmware isn't configuring multi RX queue hardware yet in the self init mode. Disable it for now until we have an API that enables it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 61cafb5415548..4c5088643b2bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1240,7 +1240,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) } /* Init RSS configuration */ - if (iwl_mvm_has_new_rx_api(mvm)) { + /* TODO - remove a000 disablement when we have RXQ config API */ + if (iwl_mvm_has_new_rx_api(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { ret = iwl_send_rss_cfg_cmd(mvm); if (ret) { IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", From c386dacb4ed681f26f6965b3e0f0448eeabfbb13 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 28 Dec 2016 15:58:22 +0200 Subject: [PATCH 110/201] iwlwifi: mvm: refactor SAR init to prepare for dynamic SAR We are adding support for dynamic TX power tables for SAR (specific absorption rate) compliance. Currently, we only support a single (static) TX power table, which is read from ACPI, and use it statically. To prepare for more tables that can be switched dynamically, refactor the SAR init flow to allow reusage and add the current static table as a single entry in an array of tables. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 155 +++++++++++-------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 17 +- 2 files changed, 107 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 4c5088643b2bf..1679104e19e9e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -990,85 +990,87 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) sizeof(cmd), &cmd); } -#define ACPI_WRDS_METHOD "WRDS" -#define ACPI_WRDS_WIFI (0x07) -#define ACPI_WRDS_TABLE_SIZE 10 +#ifdef CONFIG_ACPI +#define ACPI_WRDS_METHOD "WRDS" +#define ACPI_WRDS_WIFI (0x07) +#define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2) + +static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, + union acpi_object *table, + struct iwl_mvm_sar_profile *profile, + bool enabled) +{ + int i; -struct iwl_mvm_sar_table { - bool enabled; - u8 values[ACPI_WRDS_TABLE_SIZE]; -}; + profile->enabled = enabled; -#ifdef CONFIG_ACPI -static int iwl_mvm_sar_get_wrds(struct iwl_mvm *mvm, union acpi_object *wrds, - struct iwl_mvm_sar_table *sar_table) + for (i = 0; i < IWL_MVM_SAR_TABLE_SIZE; i++) { + if ((table[i].type != ACPI_TYPE_INTEGER) || + (table[i].integer.value > U8_MAX)) + return -EINVAL; + + profile->table[i] = table[i].integer.value; + } + + return 0; +} + +static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm, + union acpi_object *data, + int data_size) { - union acpi_object *data_pkg; - u32 i; + int i; + union acpi_object *wifi_pkg; - /* We need at least two packages, one for the revision and one + /* + * We need at least two packages, one for the revision and one * for the data itself. Also check that the revision is valid * (i.e. it is an integer set to 0). - */ - if (wrds->type != ACPI_TYPE_PACKAGE || - wrds->package.count < 2 || - wrds->package.elements[0].type != ACPI_TYPE_INTEGER || - wrds->package.elements[0].integer.value != 0) { - IWL_DEBUG_RADIO(mvm, "Unsupported wrds structure\n"); - return -EINVAL; + */ + if (data->type != ACPI_TYPE_PACKAGE || + data->package.count < 2 || + data->package.elements[0].type != ACPI_TYPE_INTEGER || + data->package.elements[0].integer.value != 0) { + IWL_DEBUG_RADIO(mvm, "Unsupported packages structure\n"); + return ERR_PTR(-EINVAL); } /* loop through all the packages to find the one for WiFi */ - for (i = 1; i < wrds->package.count; i++) { + for (i = 1; i < data->package.count; i++) { union acpi_object *domain; - data_pkg = &wrds->package.elements[i]; + wifi_pkg = &data->package.elements[i]; /* Skip anything that is not a package with the right * amount of elements (i.e. domain_type, - * enabled/disabled plus the sar table size. + * enabled/disabled plus the actual data size. */ - if (data_pkg->type != ACPI_TYPE_PACKAGE || - data_pkg->package.count != ACPI_WRDS_TABLE_SIZE + 2) + if (wifi_pkg->type != ACPI_TYPE_PACKAGE || + wifi_pkg->package.count != data_size) continue; - domain = &data_pkg->package.elements[0]; + domain = &wifi_pkg->package.elements[0]; if (domain->type == ACPI_TYPE_INTEGER && domain->integer.value == ACPI_WRDS_WIFI) break; - data_pkg = NULL; + wifi_pkg = NULL; } - if (!data_pkg) - return -ENOENT; - - if (data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) - return -EINVAL; - - sar_table->enabled = !!(data_pkg->package.elements[1].integer.value); - - for (i = 0; i < ACPI_WRDS_TABLE_SIZE; i++) { - union acpi_object *entry; - - entry = &data_pkg->package.elements[i + 2]; - if ((entry->type != ACPI_TYPE_INTEGER) || - (entry->integer.value > U8_MAX)) - return -EINVAL; - - sar_table->values[i] = entry->integer.value; - } + if (!wifi_pkg) + return ERR_PTR(-ENOENT); - return 0; + return wifi_pkg; } -static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm, - struct iwl_mvm_sar_table *sar_table) +static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) { + union acpi_object *wifi_pkg, *table; acpi_handle root_handle; acpi_handle handle; struct acpi_buffer wrds = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; + bool enabled; int ret; root_handle = ACPI_HANDLE(mvm->dev); @@ -1093,22 +1095,36 @@ static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm, return -ENOENT; } - ret = iwl_mvm_sar_get_wrds(mvm, wrds.pointer, sar_table); - kfree(wrds.pointer); + wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, wrds.pointer, + ACPI_WRDS_WIFI_DATA_SIZE); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out_free; + } + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + /* position of the actual table */ + table = &wifi_pkg->package.elements[2]; + + /* The profile from WRDS is officially profile 1, but goes + * into sar_profiles[0] (because we don't have a profile 0). + */ + ret = iwl_mvm_sar_set_profile(mvm, table, &mvm->sar_profiles[0], + enabled); + +out_free: + kfree(wrds.pointer); return ret; } -#else /* CONFIG_ACPI */ -static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm, - struct iwl_mvm_sar_table *sar_table) -{ - return -ENOENT; -} -#endif /* CONFIG_ACPI */ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { - struct iwl_mvm_sar_table sar_table; struct iwl_dev_tx_power_cmd cmd = { .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), }; @@ -1118,7 +1134,7 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) len = sizeof(cmd.v3); - ret = iwl_mvm_sar_get_table(mvm, &sar_table); + ret = iwl_mvm_sar_get_wrds_table(mvm); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "SAR BIOS table invalid or unavailable. (%d)\n", @@ -1127,22 +1143,23 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) return 0; } - if (!sar_table.enabled) + /* if profile 0 is disabled, there's nothing else to do here */ + if (!mvm->sar_profiles[0].enabled) return 0; IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != - ACPI_WRDS_TABLE_SIZE); + IWL_MVM_SAR_TABLE_SIZE); for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); for (j = 0; j < IWL_NUM_SUB_BANDS; j++) { idx = (i * IWL_NUM_SUB_BANDS) + j; cmd.v3.per_chain_restriction[i][j] = - cpu_to_le16(sar_table.values[idx]); + cpu_to_le16(mvm->sar_profiles[0].table[idx]); IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", - j, sar_table.values[idx]); + j, mvm->sar_profiles[0].table[idx]); } } @@ -1153,6 +1170,18 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) return ret; } +#else /* CONFIG_ACPI */ +static inline int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) +{ + return -ENOENT; +} + +static inline int iwl_mvm_sar_init(struct iwl_mvm *mvm) +{ + return 0; +} +#endif /* CONFIG_ACPI */ + static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) { int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 91bd5ebd5b653..0c35d9ebd4acc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -710,6 +710,16 @@ enum iwl_mvm_queue_status { #define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ) #define IWL_MVM_NUM_CIPHERS 10 +#ifdef CONFIG_ACPI +#define IWL_MVM_SAR_TABLE_SIZE 10 +#define IWL_MVM_SAR_PROFILE_NUM 1 + +struct iwl_mvm_sar_profile { + bool enabled; + u8 table[IWL_MVM_SAR_TABLE_SIZE]; +}; +#endif + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -1039,6 +1049,9 @@ struct iwl_mvm { bool drop_bcn_ap_mode; struct delayed_work cs_tx_unblock_dwork; +#ifdef CONFIG_ACPI + struct iwl_mvm_sar_profile sar_profiles[IWL_MVM_SAR_PROFILE_NUM]; +#endif }; /* Extract MVM priv from op_mode and _hw */ From 42ce76d615e7cb2b57be90ce0f357604a7903253 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 11 Jan 2017 23:36:30 +0200 Subject: [PATCH 111/201] iwlwifi: mvm: spin off SAR profile selection function For dynamic SAR, we will need to select the current profile from different places. In preparation for that, spin the profile selection code out of iwl_mvm_sar_init(). Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 73 ++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d74ae15b2d856..119a3bd92c50f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2116,6 +2116,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) */ iwl_mvm_update_changed_regdom(mvm); + if (!unified_image) + /* Re-configure default SAR profile */ + iwl_mvm_sar_select_profile(mvm, 1, 1); + if (mvm->net_detect) { /* If this is a non-unified image, we restart the FW, * so no need to stop the netdetect scan. If that diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1679104e19e9e..6360361c576de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1123,49 +1123,78 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) return ret; } -static int iwl_mvm_sar_init(struct iwl_mvm *mvm) +int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { struct iwl_dev_tx_power_cmd cmd = { .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), }; - int ret, i, j, idx; + int i, j, idx; + int profs[IWL_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; int len = sizeof(cmd); + BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS < 2); + BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != + IWL_MVM_SAR_TABLE_SIZE); + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) len = sizeof(cmd.v3); - ret = iwl_mvm_sar_get_wrds_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return 0; - } + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { + struct iwl_mvm_sar_profile *prof; - /* if profile 0 is disabled, there's nothing else to do here */ - if (!mvm->sar_profiles[0].enabled) - return 0; + /* don't allow SAR to be disabled (profile 0 means disable) */ + if (profs[i] == 0) + return -EPERM; - IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); + /* we are off by one, so allow up to IWL_MVM_SAR_PROFILE_NUM */ + if (profs[i] > IWL_MVM_SAR_PROFILE_NUM) + return -EINVAL; - BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != - IWL_MVM_SAR_TABLE_SIZE); + /* profiles go from 1 to 4, so decrement to access the array */ + prof = &mvm->sar_profiles[profs[i] - 1]; + + /* if the profile is disabled, do nothing */ + if (!prof->enabled) { + IWL_DEBUG_RADIO(mvm, "SAR profile %d is disabled.\n", + profs[i]); + /* if one of the profiles is disabled, we fail all */ + return -ENOENT; + } - for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); for (j = 0; j < IWL_NUM_SUB_BANDS; j++) { idx = (i * IWL_NUM_SUB_BANDS) + j; cmd.v3.per_chain_restriction[i][j] = - cpu_to_le16(mvm->sar_profiles[0].table[idx]); + cpu_to_le16(prof->table[idx]); IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", - j, mvm->sar_profiles[0].table[idx]); + j, prof->table[idx]); } } - ret = iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); - if (ret) - IWL_ERR(mvm, "failed to set per-chain TX power: %d\n", ret); + IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); +} + +static int iwl_mvm_sar_init(struct iwl_mvm *mvm) +{ + int ret; + + ret = iwl_mvm_sar_get_wrds_table(mvm); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + return 0; + } + + /* choose profile 1 (WRDS) as default for both chains */ + ret = iwl_mvm_sar_select_profile(mvm, 1, 1); + + /* if we don't have profile 0 from BIOS, just skip it */ + if (ret == -ENOENT) + return 0; return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 0c35d9ebd4acc..f4e8fa3765fad 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1818,5 +1818,6 @@ int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif, enum iwl_lqm_cmd_operatrions operation, u32 duration, u32 timeout); bool iwl_mvm_lqm_active(struct iwl_mvm *mvm); +int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); #endif /* __IWL_MVM_H__ */ From 6996490501ed8011964e1b1403ae2d104337843c Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Thu, 12 Jan 2017 12:43:12 +0200 Subject: [PATCH 112/201] iwlwifi: mvm: add support for EWRD (Dynamic SAR) ACPI table Dynamic SAR allows changing TX power limits at runtime to comply with SAR regulations on multiple form factors (e.g. tablet vs. clamshell mode). To support this, a new table was added to ACPI, which is called Extended Wireless Regulatory Descriptor (EWRD). This table allows OEMs to define different TX power profiles for each form-factor or usage mode. Read this new table and store it in our SAR profiles table, in preparation for Dynamic SAR support. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 114 ++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 11 +- 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6360361c576de..2a4c952ef01a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -992,8 +992,11 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) #ifdef CONFIG_ACPI #define ACPI_WRDS_METHOD "WRDS" -#define ACPI_WRDS_WIFI (0x07) +#define ACPI_EWRD_METHOD "EWRD" +#define ACPI_WIFI_DOMAIN (0x07) #define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2) +#define ACPI_EWRD_WIFI_DATA_SIZE ((IWL_MVM_SAR_PROFILE_NUM - 1) * \ + IWL_MVM_SAR_TABLE_SIZE + 3) static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, union acpi_object *table, @@ -1051,7 +1054,7 @@ static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm, domain = &wifi_pkg->package.elements[0]; if (domain->type == ACPI_TYPE_INTEGER && - domain->integer.value == ACPI_WRDS_WIFI) + domain->integer.value == ACPI_WIFI_DOMAIN) break; wifi_pkg = NULL; @@ -1123,6 +1126,78 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) return ret; } +static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) +{ + union acpi_object *wifi_pkg; + acpi_handle root_handle; + acpi_handle handle; + struct acpi_buffer ewrd = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + bool enabled; + int i, n_profiles, ret; + + root_handle = ACPI_HANDLE(mvm->dev); + if (!root_handle) { + IWL_DEBUG_RADIO(mvm, + "Could not retrieve root port ACPI handle\n"); + return -ENOENT; + } + + /* Get the method's handle */ + status = acpi_get_handle(root_handle, (acpi_string)ACPI_EWRD_METHOD, + &handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "EWRD method not found\n"); + return -ENOENT; + } + + /* Call EWRD with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &ewrd); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "EWRD invocation failed (0x%x)\n", status); + return -ENOENT; + } + + wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, ewrd.pointer, + ACPI_EWRD_WIFI_DATA_SIZE); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if ((wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) || + (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER)) { + ret = -EINVAL; + goto out_free; + } + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + n_profiles = wifi_pkg->package.elements[2].integer.value; + + for (i = 0; i < n_profiles; i++) { + /* the tables start at element 3 */ + static int pos = 3; + + /* The EWRD profiles officially go from 2 to 4, but we + * save them in sar_profiles[1-3] (because we don't + * have profile 0). So in the array we start from 1. + */ + ret = iwl_mvm_sar_set_profile(mvm, + &wifi_pkg->package.elements[pos], + &mvm->sar_profiles[i + 1], + enabled); + if (ret < 0) + break; + + /* go to the next table */ + pos += IWL_MVM_SAR_TABLE_SIZE; + } + +out_free: + kfree(ewrd.pointer); + return ret; +} + int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { struct iwl_dev_tx_power_cmd cmd = { @@ -1176,6 +1251,18 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +#else /* CONFIG_ACPI */ +static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) +{ + return -ENOENT; +} + +static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ + static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { int ret; @@ -1183,12 +1270,19 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) ret = iwl_mvm_sar_get_wrds_table(mvm); if (ret < 0) { IWL_DEBUG_RADIO(mvm, - "SAR BIOS table invalid or unavailable. (%d)\n", + "WRDS SAR BIOS table invalid or unavailable. (%d)\n", ret); - /* we don't fail if the table is not available */ + /* if not available, don't fail and don't bother with EWRD */ return 0; } + ret = iwl_mvm_sar_get_ewrd_table(mvm); + /* if EWRD is not available, we can still use WRDS, so don't fail */ + if (ret < 0) + IWL_DEBUG_RADIO(mvm, + "EWRD SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* choose profile 1 (WRDS) as default for both chains */ ret = iwl_mvm_sar_select_profile(mvm, 1, 1); @@ -1199,18 +1293,6 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) return ret; } -#else /* CONFIG_ACPI */ -static inline int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - -static inline int iwl_mvm_sar_init(struct iwl_mvm *mvm) -{ - return 0; -} -#endif /* CONFIG_ACPI */ - static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) { int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f4e8fa3765fad..2205c9f8bb587 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -712,7 +712,7 @@ enum iwl_mvm_queue_status { #ifdef CONFIG_ACPI #define IWL_MVM_SAR_TABLE_SIZE 10 -#define IWL_MVM_SAR_PROFILE_NUM 1 +#define IWL_MVM_SAR_PROFILE_NUM 4 struct iwl_mvm_sar_profile { bool enabled; @@ -1818,6 +1818,15 @@ int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif, enum iwl_lqm_cmd_operatrions operation, u32 duration, u32 timeout); bool iwl_mvm_lqm_active(struct iwl_mvm *mvm); + +#ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); +#else +static inline +int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ #endif /* __IWL_MVM_H__ */ From c47de665751027781fe07fba1959911ab194add4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 29 Sep 2016 17:28:33 +0300 Subject: [PATCH 113/201] iwlwifi: mvm: support new TX API Support the new TX command API for a000 devices. Command is a very slim version of current TX command. Generalize iwl_mvm_tx_mpdu to get rid of TX command dependencies. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/fw-api-tx.h | 42 +++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 66 ++++++++++++++----- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 85744fa3bd4d2..f83ee6e760d07 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,6 +124,20 @@ enum iwl_tx_flags { TX_CMD_FLG_HCCA_CHUNK = BIT(31) }; /* TX_FLAGS_BITS_API_S_VER_1 */ +/** + * enum iwl_tx_cmd_flags - bitmasks for tx_flags in TX command for a000 + * @IWL_TX_FLAGS_CMD_RATE: use rate from the TX command + * @IWL_TX_FLAGS_ENCRYPT_DIS: frame should not be encrypted, even if it belongs + * to a secured STA + * @IWL_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate + * selection, retry limits and BT kill + */ +enum iwl_tx_cmd_flags { + IWL_TX_FLAGS_CMD_RATE = BIT(0), + IWL_TX_FLAGS_ENCRYPT_DIS = BIT(1), + IWL_TX_FLAGS_HIGH_PRI = BIT(2), +}; /* TX_FLAGS_BITS_API_S_VER_3 */ + /** * enum iwl_tx_pm_timeouts - pm timeout values in TX command * @PM_FRAME_NONE: no need to suspend sleep mode @@ -301,6 +316,31 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; /* TX_CMD_API_S_VER_6 */ +struct iwl_dram_sec_info { + __le32 pn_low; + __le16 pn_high; + __le16 aux_info; +} __packed; /* DRAM_SEC_INFO_API_S_VER_1 */ + +/** + * struct iwl_tx_cmd_gen2 - TX command struct to FW for a000 devices + * ( TX_CMD = 0x1c ) + * @len: in bytes of the payload, see below for details + * @offload_assist: TX offload configuration + * @tx_flags: combination of &iwl_tx_cmd_flags + * @dram_info: FW internal DRAM storage + * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is + * cleared. Combination of RATE_MCS_* + */ +struct iwl_tx_cmd_gen2 { + __le16 len; + __le16 offload_assist; + __le32 flags; + struct iwl_dram_sec_info dram_info; + __le32 rate_n_flags; + struct ieee80211_hdr hdr[0]; +} __packed; /* TX_CMD_API_S_VER_7 */ + /* * TX response related data */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 00b6eaca08925..878367d9aa85a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -475,6 +475,39 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, memset(dev_cmd, 0, sizeof(*dev_cmd)); dev_cmd->hdr.cmd = TX_CMD; + + if (iwl_mvm_has_new_tx_api(mvm)) { + struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; + u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info); + + /* padding is inserted later in transport */ + /* FIXME - check for AMSDU may need to be removed */ + if (ieee80211_hdrlen(hdr->frame_control) % 4 && + !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) + offload_assist |= BIT(TX_CMD_OFFLD_PAD); + + cmd->offload_assist |= cpu_to_le16(offload_assist); + + /* Total # bytes to be transmitted */ + cmd->len = cpu_to_le16((u16)skb->len); + + /* Copy MAC header from skb into command buffer */ + memcpy(cmd->hdr, hdr, hdrlen); + + if (!info->control.hw_key) + cmd->flags |= cpu_to_le32(IWL_TX_FLAGS_ENCRYPT_DIS); + + /* For data packets rate info comes from the fw */ + if (ieee80211_is_data(hdr->frame_control) && sta) + goto out; + + cmd->flags |= cpu_to_le32(IWL_TX_FLAGS_CMD_RATE); + cmd->rate_n_flags = + cpu_to_le32(iwl_mvm_get_tx_rate(mvm, info, sta)); + + goto out; + } + tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; if (info->control.hw_key) @@ -484,6 +517,10 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdrlen); + +out: return dev_cmd; } @@ -541,7 +578,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info info; struct iwl_device_cmd *dev_cmd; - struct iwl_tx_cmd *tx_cmd; u8 sta_id; int hdrlen = ieee80211_hdrlen(hdr->frame_control); int queue; @@ -616,11 +652,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) /* From now on, we cannot access info->control */ iwl_mvm_skb_prepare_status(skb, dev_cmd); - tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; - - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdrlen); - if (iwl_trans_tx(mvm->trans, skb, dev_cmd, queue)) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); return -1; @@ -881,7 +912,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_mvm_sta *mvmsta; struct iwl_device_cmd *dev_cmd; - struct iwl_tx_cmd *tx_cmd; __le16 fc; u16 seq_number = 0; u8 tid = IWL_MAX_TID_COUNT; @@ -904,8 +934,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (!dev_cmd) goto drop; - tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; - /* * we handle that entirely ourselves -- for uAPSD the firmware * will always send a notification, and for PS-Poll responses @@ -926,18 +954,27 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) goto drop_unlock_sta; - seq_number = mvmsta->tid_data[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(seq_number); is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; if (WARN_ON_ONCE(is_ampdu && mvmsta->tid_data[tid].state != IWL_AGG_ON)) goto drop_unlock_sta; + + seq_number = mvmsta->tid_data[tid].seq_number; + seq_number &= IEEE80211_SCTL_SEQ; + + if (!iwl_mvm_has_new_tx_api(mvm)) { + struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; + + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(seq_number); + /* update the tx_cmd hdr as it was already copied */ + tx_cmd->hdr->seq_ctrl = hdr->seq_ctrl; + } } if (iwl_mvm_is_dqa_supported(mvm) || is_ampdu) txq_id = mvmsta->tid_data[tid].txq_id; + if (sta->tdls && !iwl_mvm_is_dqa_supported(mvm)) { /* default to TID 0 for non-QoS packets */ u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid; @@ -945,9 +982,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]]; } - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdrlen); - WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); /* Check if TXQ needs to be allocated or re-activated */ From 6b35ff91572f7fc42ec0026f512a8d274071163b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 29 Sep 2016 14:36:19 +0300 Subject: [PATCH 114/201] iwlwifi: pcie: introduce a000 TX queues management In a000 devices the TX handling is different in a few ways: * Queues are allocated dynamically * DQA is enabled by default * Driver shouldn't access TFH registers - ucode configures it all in SCD_QUEUE_CFG command Support all this in a new API with op mode, where op mode sends the command, transport will allocate the queue dynamically, fill in DMA properties, send the command to FW and get the ID back. Current implementation only sets the new transport API and fills the DMA properties. Future patches will complete the other parts. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 2 +- .../net/wireless/intel/iwlwifi/iwl-trans.h | 70 +++++++- .../wireless/intel/iwlwifi/pcie/internal.h | 6 + .../net/wireless/intel/iwlwifi/pcie/trans.c | 6 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 162 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 +- 6 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index b27bcac8f5db4..411cb91c102f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -7,7 +7,7 @@ iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o -iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o +iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o pcie/tx-gen2.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o iwlwifi-objs += iwl-trans.o diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 1b4b62ede2c4d..723402ee7be27 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -530,6 +530,38 @@ struct iwl_trans_txq_scd_cfg { int frame_limit; }; +/** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @token: token of the command + * @sta_id: station id + * @tid: tid of the queue + * @scd_queue: scheduler queue to config + * @action: 1 queue enable, 0 queue disable + * @aggregate: 1 aggregated queue, 0 otherwise + * @tx_fifo: TX fifo + * @window: BA window size + * @ssn: SSN for the BA agreement + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; + u8 action; + u8 aggregate; + u8 tx_fifo; + u8 window; + __le16 ssn; + __le16 reserved; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_1 */ + /** * struct iwl_trans_ops - transport specific operations * @@ -640,6 +672,12 @@ struct iwl_trans_ops { unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, bool configure_scd); + /* a000 functions */ + int (*txq_alloc)(struct iwl_trans *trans, + struct iwl_tx_queue_cfg_cmd *cmd, + int cmd_id, + unsigned int queue_wdg_timeout); + void (*txq_free)(struct iwl_trans *trans, int queue); void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, bool shared); @@ -1057,6 +1095,34 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } +static inline void +iwl_trans_txq_free(struct iwl_trans *trans, int queue) +{ + if (WARN_ON_ONCE(!trans->ops->txq_free)) + return; + + trans->ops->txq_free(trans, queue); +} + +static inline int +iwl_trans_txq_alloc(struct iwl_trans *trans, + struct iwl_tx_queue_cfg_cmd *cmd, + int cmd_id, + unsigned int queue_wdg_timeout) +{ + might_sleep(); + + if (WARN_ON_ONCE(!trans->ops->txq_alloc)) + return -ENOTSUPP; + + if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + return -EIO; + } + + return trans->ops->txq_alloc(trans, cmd, cmd_id, queue_wdg_timeout); +} + static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, int queue, bool shared_mode) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 98c1308eab0da..5e191579b9a9c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -758,10 +758,16 @@ void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); +void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill); void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr); +int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, + struct iwl_tx_queue_cfg_cmd *cmd, + int cmd_id, + unsigned int timeout); +void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 361f0b0a6f42c..9cd9c1f5a3dc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2923,10 +2923,8 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .tx = iwl_trans_pcie_tx, .reclaim = iwl_trans_pcie_reclaim, - .txq_disable = iwl_trans_pcie_txq_disable, - .txq_enable = iwl_trans_pcie_txq_enable, - - .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, + .txq_free = iwl_trans_pcie_dyn_txq_free, .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c new file mode 100644 index 0000000000000..7c93f266871e7 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include "iwl-debug.h" +#include "iwl-csr.h" +#include "iwl-io.h" +#include "internal.h" + +/* + * iwl_pcie_gen2_txq_unmap - Unmap any remaining DMA mappings and free skb's + */ +void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + + spin_lock_bh(&txq->lock); + while (txq->write_ptr != txq->read_ptr) { + IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", + txq_id, txq->read_ptr); + + iwl_pcie_txq_free_tfd(trans, txq); + txq->read_ptr = iwl_queue_inc_wrap(txq->read_ptr); + + if (txq->read_ptr == txq->write_ptr) { + unsigned long flags; + + spin_lock_irqsave(&trans_pcie->reg_lock, flags); + if (txq_id != trans_pcie->cmd_queue) { + IWL_DEBUG_RPM(trans, "Q %d - last tx freed\n", + txq->id); + iwl_trans_unref(trans); + } else if (trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = false; + IWL_DEBUG_RPM(trans, + "clear ref_cmd_in_flight\n"); + iwl_trans_unref(trans); + } + spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); + } + } + spin_unlock_bh(&txq->lock); + + /* just in case - this queue may have been stopped */ + iwl_wake_queue(trans, txq); +} + +int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, + struct iwl_tx_queue_cfg_cmd *cmd, + int cmd_id, + unsigned int timeout) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[cmd->scd_queue]; + struct iwl_host_cmd hcmd = { + .id = cmd_id, + .len = { sizeof(*cmd) }, + .data = { cmd, }, + .flags = 0, + }; + u16 ssn = le16_to_cpu(cmd->ssn); + + if (test_and_set_bit(cmd->scd_queue, trans_pcie->queue_used)) { + WARN_ONCE(1, "queue %d already used", cmd->scd_queue); + return -EINVAL; + } + + txq->wd_timeout = msecs_to_jiffies(timeout); + + /* + * Place first TFD at index corresponding to start sequence number. + * Assumes that ssn_idx is valid (!= 0xFFF) + */ + txq->read_ptr = (ssn & 0xff); + txq->write_ptr = (ssn & 0xff); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, + (ssn & 0xff) | (cmd->scd_queue << 8)); + + IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d WrPtr: %d\n", + cmd->scd_queue, ssn & 0xff); + + cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); + cmd->byte_cnt_addr = cpu_to_le64(trans_pcie->scd_bc_tbls.dma + + cmd->scd_queue * + sizeof(struct iwlagn_scd_bc_tbl)); + cmd->cb_size = cpu_to_le64(TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX)); + + return iwl_trans_send_cmd(trans, &hcmd); +} + +void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + trans_pcie->txq[queue].frozen_expiry_remainder = 0; + trans_pcie->txq[queue].frozen = false; + + /* + * Upon HW Rfkill - we stop the device, and then stop the queues + * in the op_mode. Just for the sake of the simplicity of the op_mode, + * allow the op_mode to call txq_disable after it already called + * stop_device. + */ + if (!test_and_clear_bit(queue, trans_pcie->queue_used)) { + WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status), + "queue %d not used", queue); + return; + } + + iwl_pcie_gen2_txq_unmap(trans, queue); + + IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", queue); +} + diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index b3ac1fb510095..9c903270645c1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -456,7 +456,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) +void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) { /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and * idx is bounded by n_window @@ -1359,9 +1359,6 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); - if (cfg && trans->cfg->use_tfh) - WARN_ONCE(1, "Expected no calls to SCD configuration"); - txq->wd_timeout = msecs_to_jiffies(wdg_timeout); if (cfg) { @@ -1477,9 +1474,6 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, return; } - if (configure_scd && trans->cfg->use_tfh) - WARN_ONCE(1, "Expected no calls to SCD configuration"); - if (configure_scd) { iwl_scd_txq_set_inactive(trans, txq_id); From bb49701b41deff0a8edd297357b23ffe833099eb Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 29 Sep 2016 14:52:40 +0300 Subject: [PATCH 115/201] iwlwifi: mvm: support a000 SCD queue configuration a000 devices queue management is going to change significantly. We will have 512 queues. Those queues will be assigned number by the firmware and not by the driver. In addition, due to SN offload having TX queue shared between TIDs is impossible Also, the ADD_STA command no longer updates queues status. The only point of changing queue in the SCD queue config API. From driver perspective we have here a new design: Queue sharing and inactivity checks are disabled. Once this is done, the only paths that call scd_queue_cfg command are paths that alloc and release TX queues - which will make future accommodation to queue number assignment by FW easier. Since allocating 512 queues statically is not advisable, transport will allocate the queue on demand, fill the command with DRAM data and send it. This is reflected in the new transport API. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/fw-api-sta.h | 5 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 62 +++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 3 + .../net/wireless/intel/iwlwifi/mvm/utils.c | 39 ++++++++++-- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index cd5fdf83d0403..4f8648f53879d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -351,7 +351,8 @@ struct iwl_mvm_add_sta_cmd_v7 { * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls - * @tfd_queue_msk: tfd queues used by this station + * @tfd_queue_msk: tfd queues used by this station. + * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means * that the queues used by this station are in the first 32. @@ -386,7 +387,7 @@ struct iwl_mvm_add_sta_cmd { __le16 rx_ba_window; u8 scd_queue_bank; u8 uapsd_trigger_acs; -} __packed; /* ADD_STA_CMD_API_S_VER_8 */ +} __packed; /* ADD_STA_CMD_API_S_VER_9 */ /** * struct iwl_mvm_add_sta_key_common - add/modify sta key common part diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index fb031197266ee..e51b74cd5b9fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -127,11 +127,17 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 agg_size = 0, mpdu_dens = 0; if (!update || (flags & STA_MODIFY_QUEUES)) { - add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); - if (flags & STA_MODIFY_QUEUES) - add_sta_cmd.modify_mask |= STA_MODIFY_QUEUES; + if (!iwl_mvm_has_new_tx_api(mvm)) { + add_sta_cmd.tfd_queue_msk = + cpu_to_le32(mvm_sta->tfd_queue_msk); + + if (flags & STA_MODIFY_QUEUES) + add_sta_cmd.modify_mask |= STA_MODIFY_QUEUES; + } else { + WARN_ON(flags & STA_MODIFY_QUEUES); + } } switch (sta->bandwidth) { @@ -337,6 +343,9 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, u8 sta_id; int ret; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; spin_unlock_bh(&mvm->queue_info_lock); @@ -387,6 +396,9 @@ static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) lockdep_assert_held(&mvm->mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -426,6 +438,9 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) lockdep_assert_held(&mvm->mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -468,6 +483,9 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, lockdep_assert_held(&mvm->mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(&mvm->queue_info_lock); txq_curr_ac = mvm->queue_info[queue].mac80211_ac; sta_id = mvm->queue_info[queue].ra_sta_id; @@ -512,6 +530,8 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, int i; lockdep_assert_held(&mvm->queue_info_lock); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; memset(&ac_to_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(ac_to_queue)); @@ -596,6 +616,9 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, unsigned long mq; int ret; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + /* * If the AC is lower than current one - FIFO needs to be redirected to * the lowest one of the streams in the queue. Check if this is needed @@ -757,6 +780,15 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, /* No free queue - we'll have to share */ if (queue <= 0) { + /* This shouldn't happen in new HW - we have 512 queues */ + if (WARN(iwl_mvm_has_new_tx_api(mvm), + "No available queues for tid %d on sta_id %d\n", + tid, cfg.sta_id)) { + spin_unlock_bh(&mvm->queue_info_lock); + + return queue; + } + queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac); if (queue > 0) { shared_queue = true; @@ -841,6 +873,9 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE; spin_unlock_bh(&mvmsta->lock); + if (iwl_mvm_has_new_tx_api(mvm)) + return 0; + if (!shared_queue) { ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); if (ret) @@ -880,6 +915,9 @@ static void iwl_mvm_change_queue_owner(struct iwl_mvm *mvm, int queue) lockdep_assert_held(&mvm->mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + spin_lock_bh(&mvm->queue_info_lock); tid_bitmap = mvm->queue_info[queue].tid_bitmap; spin_unlock_bh(&mvm->queue_info_lock); @@ -917,6 +955,10 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) int ssn; int ret = true; + /* queue sharing is disabled on new TX path */ + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->queue_info_lock); @@ -1675,7 +1717,8 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, color)); - cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); + if (!iwl_mvm_has_new_tx_api(mvm)) + cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); cmd.tid_disable_tx = cpu_to_le16(0xffff); if (addr) @@ -2293,7 +2336,9 @@ int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); cmd.sta_id = mvm_sta->sta_id; cmd.add_modify = STA_MODE_MODIFY; - cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX; + if (!iwl_mvm_has_new_tx_api(mvm)) + cmd.modify_mask = STA_MODIFY_QUEUES; + cmd.modify_mask |= STA_MODIFY_TID_DISABLE_TX; cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg); @@ -2493,6 +2538,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * changed from current (become smaller) */ if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) { + /* + * On new TX API rs and BA manager are offloaded. + * For now though, just don't support being reconfigured + */ + if (iwl_mvm_has_new_tx_api(mvm)) + return -ENOTSUPP; + /* * If reconfiguring an existing queue, it first must be * drained diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 878367d9aa85a..4d6683141c038 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -893,6 +893,9 @@ static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id) unsigned long now = jiffies; int tid; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return false; + for_each_set_bit(tid, &queue_tid_bitmap, IWL_MAX_TID_COUNT + 1) { if (time_before(mvm->queue_info[txq_id].last_frame_time[tid] + IWL_MVM_DQA_QUEUE_TIMEOUT, now)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 3054945b949ab..74f62851f6532 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -598,6 +598,9 @@ int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq) mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE) return i; + if (iwl_mvm_has_new_tx_api(mvm)) + return -ENOSPC; + /* * If no free queue found - settle for an inactive one to reconfigure * Make sure that the inactive queue either already belongs to this STA, @@ -628,6 +631,9 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, }; int ret; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(&mvm->queue_info_lock); if (WARN(mvm->queue_info[queue].hw_queue_refcount == 0, "Trying to reconfig unallocated queue %d\n", queue)) { @@ -696,7 +702,7 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, /* Send the enabling command if we need to */ if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, cfg->sta_id, cfg->tid)) { - struct iwl_scd_txq_cfg_cmd cmd = { + struct iwl_tx_queue_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_ENABLE_QUEUE, .window = cfg->frame_limit, @@ -707,9 +713,16 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, .tid = cfg->tid, }; + if (iwl_mvm_has_new_tx_api(mvm)) { + iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, + SCD_QUEUE_CFG, wdg_timeout); + return; + } + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); - WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, + sizeof(struct iwl_scd_txq_cfg_cmd), &cmd), "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); @@ -719,7 +732,7 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u8 tid, u8 flags) { - struct iwl_scd_txq_cfg_cmd cmd = { + struct iwl_tx_queue_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; @@ -795,9 +808,17 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, spin_unlock_bh(&mvm->queue_info_lock); - iwl_trans_txq_disable(mvm->trans, queue, false); - ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, - sizeof(cmd), &cmd); + if (iwl_mvm_has_new_tx_api(mvm)) { + iwl_trans_txq_free(mvm->trans, queue); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, + sizeof(cmd), &cmd); + } else { + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, + sizeof(struct iwl_scd_txq_cfg_cmd), + &cmd); + } + if (ret) IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", queue, ret); @@ -1096,6 +1117,9 @@ static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, lockdep_assert_held(&mvmsta->lock); lockdep_assert_held(&mvm->queue_info_lock); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + /* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { /* If some TFDs are still queued - don't mark TID as inactive */ @@ -1162,6 +1186,9 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) unsigned long now = jiffies; int i; + if (iwl_mvm_has_new_tx_api(mvm)) + return; + spin_lock_bh(&mvm->queue_info_lock); for (i = 0; i < IWL_MAX_HW_QUEUES; i++) if (mvm->queue_info[i].hw_queue_refcount > 0) From c65f4e03fc46c646f81cc659e501969ca48c3220 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 13 Dec 2016 16:10:28 +0200 Subject: [PATCH 116/201] iwlwifi: mvm: support moving to mgmt tid For a000 FW moved to 15 as management TID. The change for us is fairly local - translate old TID to 15 when enabling and disabling a queue, and make sure to cover it also on TX responses. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 723402ee7be27..c87a58ee012a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -397,6 +397,7 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) */ #define IWL_MAX_HW_QUEUES 32 #define IWL_MAX_TID_COUNT 8 +#define IWL_MGMT_TID 15 #define IWL_FRAME_LIMIT 64 #define IWL_MAX_RX_HW_QUEUES 16 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 4d6683141c038..4ba7ff44420da 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1425,7 +1425,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (!IS_ERR(sta)) { mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (tid != IWL_TID_NON_QOS) { + if (tid != IWL_TID_NON_QOS && tid != IWL_MGMT_TID) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; bool send_eosp_ndp = false; @@ -1767,8 +1767,11 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) * This will go together with SN and AddBA offload and cannot * be handled properly for now. */ - WARN_ON(le16_to_cpu(ba_res->tfd_cnt) != 1); - iwl_mvm_tx_reclaim(mvm, sta_id, ba_res->ra_tid[0].tid, + WARN_ON(le16_to_cpu(ba_res->ra_tid_cnt) != 1); + tid = ba_res->ra_tid[0].tid; + if (tid == IWL_MGMT_TID) + tid = IWL_MAX_TID_COUNT; + iwl_mvm_tx_reclaim(mvm, sta_id, tid, (int)ba_res->tfd[0].q_num, le16_to_cpu(ba_res->tfd[0].tfd_index), &ba_info, le32_to_cpu(ba_res->tx_rate)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 74f62851f6532..70ec048ac1525 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -714,6 +714,8 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, }; if (iwl_mvm_has_new_tx_api(mvm)) { + if (cmd.tid == IWL_MAX_TID_COUNT) + cmd.tid = IWL_MGMT_TID; iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, SCD_QUEUE_CFG, wdg_timeout); return; @@ -810,6 +812,8 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, if (iwl_mvm_has_new_tx_api(mvm)) { iwl_trans_txq_free(mvm->trans, queue); + if (cmd.tid == IWL_MAX_TID_COUNT) + cmd.tid = IWL_MGMT_TID; ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, sizeof(cmd), &cmd); } else { From ab6c644539e98be3d73702c84f8f9efc789391f0 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 1 Nov 2016 12:37:49 +0200 Subject: [PATCH 117/201] iwlwifi: pcie: copy TX functions to new transport This is just a copy-paste in order to make changes tracking easier. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 13 + .../net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 519 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 38 +- 4 files changed, 540 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 5e191579b9a9c..b9afffae8a4da 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -650,6 +650,12 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) } } +static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, + struct iwl_txq *txq, int idx) +{ + return txq->tfds + trans_pcie->tfd_size * idx; +} + static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -759,6 +765,11 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); +int iwl_queue_space(const struct iwl_txq *q); +int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -769,5 +780,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, int cmd_id, unsigned int timeout); void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); +int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, int txq_id); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 9cd9c1f5a3dc9..e1610241be07c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2920,7 +2920,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .send_cmd = iwl_trans_pcie_send_hcmd, - .tx = iwl_trans_pcie_tx, + .tx = iwl_trans_pcie_gen2_tx, .reclaim = iwl_trans_pcie_reclaim, .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 7c93f266871e7..2ddaf7a1a1b59 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -53,6 +53,525 @@ #include "iwl-csr.h" #include "iwl-io.h" #include "internal.h" +#include "mvm/fw-api.h" + +/* + * iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array + */ +static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, + struct iwl_txq *txq, u16 byte_cnt, + int num_tbs) +{ + struct iwlagn_scd_bc_tbl *scd_bc_tbl; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int write_ptr = txq->write_ptr; + u8 filled_tfd_size, num_fetch_chunks; + u16 len = byte_cnt; + __le16 bc_ent; + + scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; + + len = DIV_ROUND_UP(len, 4); + + if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) + return; + + filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) + + num_tbs * sizeof(struct iwl_tfh_tb); + /* + * filled_tfd_size contains the number of filled bytes in the TFD. + * Dividing it by 64 will give the number of chunks to fetch + * to SRAM- 0 for one chunk, 1 for 2 and so on. + * If, for example, TFD contains only 3 TBs then 32 bytes + * of the TFD are used, and only one chunk of 64 bytes should + * be fetched + */ + num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; + + bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12)); + scd_bc_tbl[txq->id].tfd_offset[write_ptr] = bc_ent; +} + +/* + * iwl_pcie_gen2_txq_inc_wr_ptr - Send new write index to hardware + */ +static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, + struct iwl_txq *txq) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 reg = 0; + int txq_id = txq->id; + + lockdep_assert_held(&txq->lock); + + /* + * explicitly wake up the NIC if: + * 1. shadow registers aren't enabled + * 2. NIC is woken up for CMD regardless of shadow outside this function + * 3. there is a chance that the NIC is asleep + */ + if (!trans->cfg->base_params->shadow_reg_enable && + txq_id != trans_pcie->cmd_queue && + test_bit(STATUS_TPOWER_PMI, &trans->status)) { + /* + * wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. + */ + reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(trans, + "Tx queue %d requesting wakeup, GP1 = 0x%x\n", + txq_id, reg); + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + txq->need_update = true; + return; + } + } + + /* + * if not in power-save mode, uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). + */ + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->write_ptr); + if (!txq->block) + iwl_write32(trans, HBUS_TARG_WRPTR, + txq->write_ptr | (txq_id << 8)); +} + +static inline u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, void *_tfd) +{ + if (trans->cfg->use_tfh) { + struct iwl_tfh_tfd *tfd = _tfd; + + return le16_to_cpu(tfd->num_tbs) & 0x1f; + } else { + struct iwl_tfd *tfd = _tfd; + + return tfd->num_tbs & 0x1f; + } +} + +static inline dma_addr_t iwl_pcie_gen2_tb_get_addr(struct iwl_trans *trans, + void *_tfd, u8 idx) +{ + if (trans->cfg->use_tfh) { + struct iwl_tfh_tfd *tfd = _tfd; + struct iwl_tfh_tb *tb = &tfd->tbs[idx]; + + return (dma_addr_t)(le64_to_cpu(tb->addr)); + } else { + struct iwl_tfd *tfd = _tfd; + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + dma_addr_t addr = get_unaligned_le32(&tb->lo); + dma_addr_t hi_len; + + if (sizeof(dma_addr_t) <= sizeof(u32)) + return addr; + + hi_len = le16_to_cpu(tb->hi_n_len) & 0xF; + + /* + * shift by 16 twice to avoid warnings on 32-bit + * (where this code never runs anyway due to the + * if statement above) + */ + return addr | ((hi_len << 16) << 16); + } +} + +static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, + struct iwl_cmd_meta *meta, + struct iwl_txq *txq, int index) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i, num_tbs; + void *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); + + /* Sanity check on number of chunks */ + num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); + + if (num_tbs >= trans_pcie->max_tbs) { + IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); + /* @todo issue fatal error, it is quite serious situation */ + return; + } + + /* first TB is never freed - it's the bidirectional DMA data */ + + for (i = 1; i < num_tbs; i++) { + if (meta->tbs & BIT(i)) + dma_unmap_page(trans->dev, + iwl_pcie_gen2_tb_get_addr(trans, tfd, + i), + iwl_pcie_gen2_tb_get_addr(trans, tfd, + i), + DMA_TO_DEVICE); + else + dma_unmap_single(trans->dev, + iwl_pcie_gen2_tb_get_addr(trans, tfd, + i), + iwl_pcie_gen2_tb_get_addr(trans, tfd, + i), + DMA_TO_DEVICE); + } + + if (trans->cfg->use_tfh) { + struct iwl_tfh_tfd *tfd_fh = (void *)tfd; + + tfd_fh->num_tbs = 0; + } else { + struct iwl_tfd *tfd_fh = (void *)tfd; + + tfd_fh->num_tbs = 0; + } +} + +static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) +{ + /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and + * idx is bounded by n_window + */ + int rd_ptr = txq->read_ptr; + int idx = get_cmd_index(txq, rd_ptr); + + lockdep_assert_held(&txq->lock); + + /* We have only q->n_window txq->entries, but we use + * TFD_QUEUE_SIZE_MAX tfds + */ + iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, txq, rd_ptr); + + /* free SKB */ + if (txq->entries) { + struct sk_buff *skb; + + skb = txq->entries[idx].skb; + + /* Can be called from irqs-disabled context + * If skb is not NULL, it means that the whole queue is being + * freed and that the queue is not empty - free the skb + */ + if (skb) { + iwl_op_mode_free_skb(trans->op_mode, skb); + txq->entries[idx].skb = NULL; + } + } +} + +static inline void iwl_pcie_gen2_set_tb(struct iwl_trans *trans, void *tfd, + u8 idx, dma_addr_t addr, u16 len) +{ + if (trans->cfg->use_tfh) { + struct iwl_tfh_tfd *tfd_fh = (void *)tfd; + struct iwl_tfh_tb *tb = &tfd_fh->tbs[idx]; + + put_unaligned_le64(addr, &tb->addr); + tb->tb_len = cpu_to_le16(len); + + tfd_fh->num_tbs = cpu_to_le16(idx + 1); + } else { + struct iwl_tfd *tfd_fh = (void *)tfd; + struct iwl_tfd_tb *tb = &tfd_fh->tbs[idx]; + + u16 hi_n_len = len << 4; + + put_unaligned_le32(addr, &tb->lo); + hi_n_len |= iwl_get_dma_hi_addr(addr); + + tb->hi_n_len = cpu_to_le16(hi_n_len); + + tfd_fh->num_tbs = idx + 1; + } +} + +int iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, + dma_addr_t addr, u16 len, bool reset) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + void *tfd; + u32 num_tbs; + + tfd = txq->tfds + trans_pcie->tfd_size * txq->write_ptr; + + if (reset) + memset(tfd, 0, trans_pcie->tfd_size); + + num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); + + /* Each TFD can point to a maximum max_tbs Tx buffers */ + if (num_tbs >= trans_pcie->max_tbs) { + IWL_ERR(trans, "Error can not send more than %d chunks\n", + trans_pcie->max_tbs); + return -EINVAL; + } + + if (WARN(addr & ~IWL_TX_DMA_MASK, + "Unaligned address = %llx\n", (unsigned long long)addr)) + return -EINVAL; + + iwl_pcie_gen2_set_tb(trans, tfd, num_tbs, addr, len); + + return num_tbs; +} + +static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u16 tb2_len; + int i; + + /* + * Set up TFD's third entry to point directly to remainder + * of skb's head, if any + */ + tb2_len = skb_headlen(skb) - hdr_len; + + if (tb2_len > 0) { + dma_addr_t tb2_phys = dma_map_single(trans->dev, + skb->data + hdr_len, + tb2_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { + iwl_pcie_gen2_tfd_unmap(trans, out_meta, txq, + txq->write_ptr); + return -EINVAL; + } + iwl_pcie_gen2_build_tfd(trans, txq, tb2_phys, tb2_len, false); + } + + /* set up the remaining entries to point to the data */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t tb_phys; + int tb_idx; + + if (!skb_frag_size(frag)) + continue; + + tb_phys = skb_frag_dma_map(trans->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + iwl_pcie_gen2_tfd_unmap(trans, out_meta, txq, + txq->write_ptr); + return -EINVAL; + } + tb_idx = iwl_pcie_gen2_build_tfd(trans, txq, tb_phys, + skb_frag_size(frag), false); + + out_meta->tbs |= BIT(tb_idx); + } + + trace_iwlwifi_dev_tx(trans->dev, skb, + iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), + trans_pcie->tfd_size, + &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, + skb->data + hdr_len, tb2_len); + trace_iwlwifi_dev_tx_data(trans->dev, skb, + hdr_len, skb->len - hdr_len); + return 0; +} + +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(TX_CMD_FLG_MH_PAD) + +int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct ieee80211_hdr *hdr; + struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; + struct iwl_cmd_meta *out_meta; + struct iwl_txq *txq; + dma_addr_t tb0_phys, tb1_phys, scratch_phys; + void *tb1_addr; + void *tfd; + u16 len, tb1_len; + bool wait_write_ptr; + __le16 fc; + u8 hdr_len; + u16 wifi_seq; + bool amsdu; + + txq = &trans_pcie->txq[txq_id]; + + if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), + "TX on unused queue %d\n", txq_id)) + return -EINVAL; + + if (unlikely(trans_pcie->sw_csum_tx && + skb->ip_summed == CHECKSUM_PARTIAL)) { + int offs = skb_checksum_start_offset(skb); + int csum_offs = offs + skb->csum_offset; + __wsum csum; + + if (skb_ensure_writable(skb, csum_offs + sizeof(__sum16))) + return -1; + + csum = skb_checksum(skb, offs, skb->len - offs, 0); + *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum); + + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + + if (skb_is_nonlinear(skb) && + skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS(trans_pcie) && + __skb_linearize(skb)) + return -ENOMEM; + + /* mac80211 always puts the full header into the SKB's head, + * so there's no need to check if it's readable there + */ + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + hdr_len = ieee80211_hdrlen(fc); + + spin_lock(&txq->lock); + + if (iwl_queue_space(txq) < txq->high_mark) { + iwl_stop_queue(trans, txq); + + /* don't put the packet on the ring, if there is no room */ + if (unlikely(iwl_queue_space(txq) < 3)) { + struct iwl_device_cmd **dev_cmd_ptr; + + dev_cmd_ptr = (void *)((u8 *)skb->cb + + trans_pcie->dev_cmd_offs); + + *dev_cmd_ptr = dev_cmd; + __skb_queue_tail(&txq->overflow_q, skb); + + spin_unlock(&txq->lock); + return 0; + } + } + + /* In AGG mode, the index in the ring must correspond to the WiFi + * sequence number. This is a HW requirements to help the SCD to parse + * the BA. + * Check here that the packets are in the right place on the ring. + */ + wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + WARN_ONCE(txq->ampdu && + (wifi_seq & 0xff) != txq->write_ptr, + "Q: %d WiFi Seq %d tfdNum %d", + txq_id, wifi_seq, txq->write_ptr); + + /* Set up driver data for this TFD */ + txq->entries[txq->write_ptr].skb = skb; + txq->entries[txq->write_ptr].cmd = dev_cmd; + + dev_cmd->hdr.sequence = + cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(txq->write_ptr))); + + tb0_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); + scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_meta = &txq->entries[txq->write_ptr].meta; + out_meta->flags = 0; + + /* + * The second TB (tb1) points to the remainder of the TX command + * and the 802.11 header - dword aligned size + * (This calculation modifies the TX command, so do it before the + * setup of the first TB) + */ + len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + + hdr_len - IWL_FIRST_TB_SIZE; + /* do not align A-MSDU to dword as the subframe header aligns it */ + amsdu = ieee80211_is_data_qos(fc) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CTL_A_MSDU_PRESENT); + if (trans_pcie->sw_csum_tx || !amsdu) { + tb1_len = ALIGN(len, 4); + /* Tell NIC about any 2-byte padding after MAC header */ + if (tb1_len != len) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + } else { + tb1_len = len; + } + + /* + * The first TB points to bi-directional DMA data, we'll + * memcpy the data into it later. + */ + iwl_pcie_gen2_build_tfd(trans, txq, tb0_phys, IWL_FIRST_TB_SIZE, true); + + /* there must be data left over for TB1 or this code must be changed */ + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE); + + /* map the data for TB1 */ + tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; + tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) + goto out_err; + iwl_pcie_gen2_build_tfd(trans, txq, tb1_phys, tb1_len, false); + + if (amsdu) { + if (unlikely(iwl_fill_data_tbs_amsdu(trans, skb, txq, hdr_len, + out_meta, dev_cmd, + tb1_len))) + goto out_err; + } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, + out_meta, dev_cmd, tb1_len))) { + goto out_err; + } + + /* building the A-MSDU might have changed this data, so memcpy it now */ + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); + + tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + /* Set up entry for this TFD in Tx byte-count array */ + iwl_pcie_gen2_update_byte_tbl(trans, txq, le16_to_cpu(tx_cmd->len), + iwl_pcie_gen2_get_num_tbs(trans, tfd)); + + wait_write_ptr = ieee80211_has_morefrags(fc); + + /* start timer if queue currently empty */ + if (txq->read_ptr == txq->write_ptr) { + if (txq->wd_timeout) { + /* + * If the TXQ is active, then set the timer, if not, + * set the timer in remainder so that the timer will + * be armed with the right value when the station will + * wake up. + */ + if (!txq->frozen) + mod_timer(&txq->stuck_timer, + jiffies + txq->wd_timeout); + else + txq->frozen_expiry_remainder = txq->wd_timeout; + } + IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", txq->id); + iwl_trans_ref(trans); + } + + /* Tell device the write index *just past* this latest filled TFD */ + txq->write_ptr = iwl_queue_inc_wrap(txq->write_ptr); + if (!wait_write_ptr) + iwl_pcie_gen2_txq_inc_wr_ptr(trans, txq); + + /* + * At this point the frame is "transmitted" successfully + * and we will get a TX status notification eventually. + */ + spin_unlock(&txq->lock); + return 0; +out_err: + spin_unlock(&txq->lock); + return -1; +} /* * iwl_pcie_gen2_txq_unmap - Unmap any remaining DMA mappings and free skb's diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9c903270645c1..9572330e22c0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -71,7 +71,7 @@ * ***************************************************/ -static int iwl_queue_space(const struct iwl_txq *q) +int iwl_queue_space(const struct iwl_txq *q) { unsigned int max; unsigned int used; @@ -185,6 +185,7 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, __le16 bc_ent; struct iwl_tx_cmd *tx_cmd = (void *)txq->entries[txq->write_ptr].cmd->payload; + u8 sta_id = tx_cmd->sta_id; scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; @@ -207,26 +208,7 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) return; - if (trans->cfg->use_tfh) { - u8 filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) + - num_tbs * sizeof(struct iwl_tfh_tb); - /* - * filled_tfd_size contains the number of filled bytes in the - * TFD. - * Dividing it by 64 will give the number of chunks to fetch - * to SRAM- 0 for one chunk, 1 for 2 and so on. - * If, for example, TFD contains only 3 TBs then 32 bytes - * of the TFD are used, and only one chunk of 64 bytes should - * be fetched - */ - u8 num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; - - bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12)); - } else { - u8 sta_id = tx_cmd->sta_id; - - bc_ent = cpu_to_le16(len | (sta_id << 12)); - } + bc_ent = cpu_to_le16(len | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; @@ -327,12 +309,6 @@ void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans) } } -static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq, int idx) -{ - return txq->tfds + trans_pcie->tfd_size * idx; -} - static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_trans *trans, void *_tfd, u8 idx) { @@ -2104,10 +2080,10 @@ static void iwl_compute_pseudo_hdr_csum(void *iph, struct tcphdr *tcph, } } -static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len) +int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) { struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; From fd2103570125be186cdb0115abc2fecb6e582aa4 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 24 Jan 2017 09:40:43 +0200 Subject: [PATCH 118/201] iwlwifi: mvm: remove unnecessary debugging from UMAC scan There are several occasions where a scan of the same type is requested concurrently, so logging every time this happens is just noisy and unnecessary. Remove the logging for these cases. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index ce6a2b3b021e5..9668f945b4e6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1037,11 +1037,8 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) return -ENOBUFS; - if (type == mvm->scan_type) { - IWL_DEBUG_SCAN(mvm, - "Ignoring UMAC scan config of the same type\n"); + if (type == mvm->scan_type) return 0; - } if (iwl_mvm_has_new_tx_api(mvm)) cmd_size = sizeof(struct iwl_scan_config); From c80eb570f8ce188e92a1693774a24d0f227985b5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 12 Jan 2017 15:43:57 +0200 Subject: [PATCH 119/201] iwlwifi: mvm: tell the firmware about the U-APSD parameters Newer firmware versions will be able to handle all the WMM-PS flows internally when we act as a GO. The firwmare relies on the fact that the drivers puts frames for different peers in different queues (DQA) to achieve this. The driver will not be aware of the power state of the peers anymore. Tell the firmware about the WMM-PS parameters of earch peer that connects to us so that it can know what are the trigger-enabled ACs, the delivery-enableds ACs and the Service Period length. This API change is backward compatible since older firmware versions will simply ignore the newly added values. Since we don't support ieee80211 TSPECs for now, just copy the trigger-enabled ACs to the delivery enabled ones. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 11 ++++++----- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 ++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 4f8648f53879d..e79df1c53d683 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -179,7 +179,7 @@ enum iwl_sta_key_flag { * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed * @STA_MODIFY_QUEUE_REMOVAL: this command removes a queue * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx - * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_trigger_acs + * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_acs * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count @@ -354,8 +354,9 @@ struct iwl_mvm_add_sta_cmd_v7 { * @tfd_queue_msk: tfd queues used by this station. * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size - * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means - * that the queues used by this station are in the first 32. + * @sp_length: the size of the SP as it appears in the WME IE + * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver + * enabled ACs. * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx @@ -385,8 +386,8 @@ struct iwl_mvm_add_sta_cmd { __le16 beamform_flags; __le32 tfd_queue_msk; __le16 rx_ba_window; - u8 scd_queue_bank; - u8 uapsd_trigger_acs; + u8 sp_length; + u8 uapsd_acs; } __packed; /* ADD_STA_CMD_API_S_VER_9 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index e51b74cd5b9fa..36ae228c16125 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -215,13 +215,15 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, add_sta_cmd.modify_mask |= STA_MODIFY_UAPSD_ACS; if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BK); + add_sta_cmd.uapsd_acs |= BIT(AC_BK); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BE); + add_sta_cmd.uapsd_acs |= BIT(AC_BE); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VI); + add_sta_cmd.uapsd_acs |= BIT(AC_VI); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VO); + add_sta_cmd.uapsd_acs |= BIT(AC_VO); + add_sta_cmd.uapsd_acs |= add_sta_cmd.uapsd_acs << 4; + add_sta_cmd.sp_length = sta->max_sp; } status = ADD_STA_SUCCESS; From cfbeb5982467f38bdde2d522b3d457d5fc94ab0c Mon Sep 17 00:00:00 2001 From: "Goodstein, Mordechay" Date: Mon, 21 Nov 2016 10:26:36 +0200 Subject: [PATCH 120/201] iwlwifi: mvm: move new API code to the end By moving all the code that depends on the new API we avoid unnecessary indentation in the code. Signed-off-by: Mordechai Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 69 +++++++++++---------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 861d54641d1e2..655bd13841582 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -649,6 +649,9 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, .mvm = mvm, }; int expected_size; + int i; + u8 *energy; + __le32 *bytes, *air_time; if (iwl_mvm_is_cdb_supported(mvm)) expected_size = sizeof(*stats); @@ -674,38 +677,6 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, le64_to_cpu(stats->general.common.on_time_scan); data.general = &stats->general; - if (iwl_mvm_has_new_rx_api(mvm)) { - int i; - u8 *energy; - __le32 *bytes, *air_time; - - if (!iwl_mvm_is_cdb_supported(mvm)) { - struct iwl_notif_statistics_v11 *v11 = - (void *)&pkt->data; - - energy = (void *)&v11->load_stats.avg_energy; - bytes = (void *)&v11->load_stats.byte_count; - air_time = (void *)&v11->load_stats.air_time; - } else { - energy = (void *)&stats->load_stats.avg_energy; - bytes = (void *)&stats->load_stats.byte_count; - air_time = (void *)&stats->load_stats.air_time; - } - - rcu_read_lock(); - for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { - struct iwl_mvm_sta *sta; - - if (!energy[i]) - continue; - - sta = iwl_mvm_sta_from_staid_rcu(mvm, i); - if (!sta) - continue; - sta->avg_energy = energy[i]; - } - rcu_read_unlock(); - } iwl_mvm_rx_stats_check_trigger(mvm, pkt); @@ -713,7 +684,39 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator, &data); + + if (!iwl_mvm_has_new_rx_api(mvm)) + return; + + if (!iwl_mvm_is_cdb_supported(mvm)) { + struct iwl_notif_statistics_v11 *v11 = + (void *)&pkt->data; + + energy = (void *)&v11->load_stats.avg_energy; + bytes = (void *)&v11->load_stats.byte_count; + air_time = (void *)&v11->load_stats.air_time; + } else { + energy = (void *)&stats->load_stats.avg_energy; + bytes = (void *)&stats->load_stats.byte_count; + air_time = (void *)&stats->load_stats.air_time; + } + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { + struct iwl_mvm_sta *sta; + + if (!energy[i]) + continue; + + sta = iwl_mvm_sta_from_staid_rcu(mvm, i); + if (!sta) + continue; + sta->avg_energy = energy[i]; + } + rcu_read_unlock(); + return; + invalid: IWL_ERR(mvm, "received invalid statistics size (%d)!\n", iwl_rx_packet_payload_len(pkt)); From 066fd29a2fa366fd87c3d1da4cd25f4dfdece1bc Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 24 Jan 2017 14:53:11 +0200 Subject: [PATCH 121/201] iwlwifi: pcie: cleanup old transport code from gen2 Cleanup code that is irrelevant for a000 devices. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 4 - .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 195 +++--------------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 +- 3 files changed, 30 insertions(+), 177 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index b9afffae8a4da..bd358895caee7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -766,10 +766,6 @@ void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); -int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 2ddaf7a1a1b59..3a36bda5fd278 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -98,88 +98,23 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 reg = 0; - int txq_id = txq->id; - lockdep_assert_held(&txq->lock); - /* - * explicitly wake up the NIC if: - * 1. shadow registers aren't enabled - * 2. NIC is woken up for CMD regardless of shadow outside this function - * 3. there is a chance that the NIC is asleep - */ - if (!trans->cfg->base_params->shadow_reg_enable && - txq_id != trans_pcie->cmd_queue && - test_bit(STATUS_TPOWER_PMI, &trans->status)) { - /* - * wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. - */ - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(trans, - "Tx queue %d requesting wakeup, GP1 = 0x%x\n", - txq_id, reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - txq->need_update = true; - return; - } - } + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq->id, txq->write_ptr); /* * if not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ - IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->write_ptr); if (!txq->block) iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq_id << 8)); + txq->write_ptr | (txq->id << 8)); } -static inline u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, void *_tfd) +static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, + struct iwl_tfh_tfd *tfd) { - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd = _tfd; - - return le16_to_cpu(tfd->num_tbs) & 0x1f; - } else { - struct iwl_tfd *tfd = _tfd; - - return tfd->num_tbs & 0x1f; - } -} - -static inline dma_addr_t iwl_pcie_gen2_tb_get_addr(struct iwl_trans *trans, - void *_tfd, u8 idx) -{ - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd = _tfd; - struct iwl_tfh_tb *tb = &tfd->tbs[idx]; - - return (dma_addr_t)(le64_to_cpu(tb->addr)); - } else { - struct iwl_tfd *tfd = _tfd; - struct iwl_tfd_tb *tb = &tfd->tbs[idx]; - dma_addr_t addr = get_unaligned_le32(&tb->lo); - dma_addr_t hi_len; - - if (sizeof(dma_addr_t) <= sizeof(u32)) - return addr; - - hi_len = le16_to_cpu(tb->hi_n_len) & 0xF; - - /* - * shift by 16 twice to avoid warnings on 32-bit - * (where this code never runs anyway due to the - * if statement above) - */ - return addr | ((hi_len << 16) << 16); - } + return le16_to_cpu(tfd->num_tbs) & 0x1f; } static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, @@ -188,45 +123,31 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i, num_tbs; - void *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); + struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); /* Sanity check on number of chunks */ num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); if (num_tbs >= trans_pcie->max_tbs) { IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); - /* @todo issue fatal error, it is quite serious situation */ return; } /* first TB is never freed - it's the bidirectional DMA data */ - for (i = 1; i < num_tbs; i++) { if (meta->tbs & BIT(i)) dma_unmap_page(trans->dev, - iwl_pcie_gen2_tb_get_addr(trans, tfd, - i), - iwl_pcie_gen2_tb_get_addr(trans, tfd, - i), + le64_to_cpu(tfd->tbs[i].addr), + le16_to_cpu(tfd->tbs[i].tb_len), DMA_TO_DEVICE); else dma_unmap_single(trans->dev, - iwl_pcie_gen2_tb_get_addr(trans, tfd, - i), - iwl_pcie_gen2_tb_get_addr(trans, tfd, - i), + le64_to_cpu(tfd->tbs[i].addr), + le16_to_cpu(tfd->tbs[i].tb_len), DMA_TO_DEVICE); } - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd_fh = (void *)tfd; - - tfd_fh->num_tbs = 0; - } else { - struct iwl_tfd *tfd_fh = (void *)tfd; - - tfd_fh->num_tbs = 0; - } + tfd->num_tbs = 0; } static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) @@ -264,27 +185,13 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) static inline void iwl_pcie_gen2_set_tb(struct iwl_trans *trans, void *tfd, u8 idx, dma_addr_t addr, u16 len) { - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd_fh = (void *)tfd; - struct iwl_tfh_tb *tb = &tfd_fh->tbs[idx]; - - put_unaligned_le64(addr, &tb->addr); - tb->tb_len = cpu_to_le16(len); - - tfd_fh->num_tbs = cpu_to_le16(idx + 1); - } else { - struct iwl_tfd *tfd_fh = (void *)tfd; - struct iwl_tfd_tb *tb = &tfd_fh->tbs[idx]; + struct iwl_tfh_tfd *tfd_fh = (void *)tfd; + struct iwl_tfh_tb *tb = &tfd_fh->tbs[idx]; - u16 hi_n_len = len << 4; + put_unaligned_le64(addr, &tb->addr); + tb->tb_len = cpu_to_le16(len); - put_unaligned_le32(addr, &tb->lo); - hi_n_len |= iwl_get_dma_hi_addr(addr); - - tb->hi_n_len = cpu_to_le16(hi_n_len); - - tfd_fh->num_tbs = idx + 1; - } + tfd_fh->num_tbs = cpu_to_le16(idx + 1); } int iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, @@ -391,11 +298,9 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, void *tb1_addr; void *tfd; u16 len, tb1_len; - bool wait_write_ptr; __le16 fc; u8 hdr_len; u16 wifi_seq; - bool amsdu; txq = &trans_pcie->txq[txq_id]; @@ -403,21 +308,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, "TX on unused queue %d\n", txq_id)) return -EINVAL; - if (unlikely(trans_pcie->sw_csum_tx && - skb->ip_summed == CHECKSUM_PARTIAL)) { - int offs = skb_checksum_start_offset(skb); - int csum_offs = offs + skb->csum_offset; - __wsum csum; - - if (skb_ensure_writable(skb, csum_offs + sizeof(__sum16))) - return -1; - - csum = skb_checksum(skb, offs, skb->len - offs, 0); - *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum); - - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (skb_is_nonlinear(skb) && skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS(trans_pcie) && __skb_linearize(skb)) @@ -432,24 +322,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_lock(&txq->lock); - if (iwl_queue_space(txq) < txq->high_mark) { - iwl_stop_queue(trans, txq); - - /* don't put the packet on the ring, if there is no room */ - if (unlikely(iwl_queue_space(txq) < 3)) { - struct iwl_device_cmd **dev_cmd_ptr; - - dev_cmd_ptr = (void *)((u8 *)skb->cb + - trans_pcie->dev_cmd_offs); - - *dev_cmd_ptr = dev_cmd; - __skb_queue_tail(&txq->overflow_q, skb); - - spin_unlock(&txq->lock); - return 0; - } - } - /* In AGG mode, the index in the ring must correspond to the WiFi * sequence number. This is a HW requirements to help the SCD to parse * the BA. @@ -488,18 +360,10 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, */ len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len - IWL_FIRST_TB_SIZE; - /* do not align A-MSDU to dword as the subframe header aligns it */ - amsdu = ieee80211_is_data_qos(fc) && - (*ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_A_MSDU_PRESENT); - if (trans_pcie->sw_csum_tx || !amsdu) { - tb1_len = ALIGN(len, 4); - /* Tell NIC about any 2-byte padding after MAC header */ - if (tb1_len != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - } else { - tb1_len = len; - } + tb1_len = ALIGN(len, 4); + /* Tell NIC about any 2-byte padding after MAC header */ + if (tb1_len != len) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; /* * The first TB points to bi-directional DMA data, we'll @@ -517,15 +381,9 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, goto out_err; iwl_pcie_gen2_build_tfd(trans, txq, tb1_phys, tb1_len, false); - if (amsdu) { - if (unlikely(iwl_fill_data_tbs_amsdu(trans, skb, txq, hdr_len, - out_meta, dev_cmd, - tb1_len))) - goto out_err; - } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, - out_meta, dev_cmd, tb1_len))) { + if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, + out_meta, dev_cmd, tb1_len))) goto out_err; - } /* building the A-MSDU might have changed this data, so memcpy it now */ memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, @@ -536,8 +394,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_gen2_update_byte_tbl(trans, txq, le16_to_cpu(tx_cmd->len), iwl_pcie_gen2_get_num_tbs(trans, tfd)); - wait_write_ptr = ieee80211_has_morefrags(fc); - /* start timer if queue currently empty */ if (txq->read_ptr == txq->write_ptr) { if (txq->wd_timeout) { @@ -559,8 +415,9 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Tell device the write index *just past* this latest filled TFD */ txq->write_ptr = iwl_queue_inc_wrap(txq->write_ptr); - if (!wait_write_ptr) - iwl_pcie_gen2_txq_inc_wr_ptr(trans, txq); + iwl_pcie_gen2_txq_inc_wr_ptr(trans, txq); + if (iwl_queue_space(txq) < txq->high_mark) + iwl_stop_queue(trans, txq); /* * At this point the frame is "transmitted" successfully @@ -586,7 +443,7 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, txq->read_ptr); - iwl_pcie_txq_free_tfd(trans, txq); + iwl_pcie_gen2_free_tfd(trans, txq); txq->read_ptr = iwl_queue_inc_wrap(txq->read_ptr); if (txq->read_ptr == txq->write_ptr) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9572330e22c0a..d57310eaaef72 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2080,10 +2080,10 @@ static void iwl_compute_pseudo_hdr_csum(void *iph, struct tcphdr *tcph, } } -int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len) +static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len) { struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; From b97277ccc61d11d354b6a7d027c6316cadc76676 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 24 Jan 2017 15:29:57 +0200 Subject: [PATCH 122/201] iwlwifi: pcie: support new TX command Move to use the correct structure. Remove code referring to old command. Update DMA locations. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index bd358895caee7..912d475ed2926 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -205,11 +205,11 @@ struct iwl_cmd_meta { * into the buffer regardless of whether it should be mapped or not. * This indicates how big the first TB must be to include the scratch buffer * and the assigned PN. - * Since PN location is 16 bytes at offset 24, it's 40 now. + * Since PN location is 8 bytes at offset 12, it's 20 now. * If we make it bigger then allocations will be bigger and copy slower, so * that's probably not useful. */ -#define IWL_FIRST_TB_SIZE 40 +#define IWL_FIRST_TB_SIZE 20 #define IWL_FIRST_TB_SIZE_ALIGN ALIGN(IWL_FIRST_TB_SIZE, 64) struct iwl_pcie_txq_entry { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 3a36bda5fd278..67af73ef7d0d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -284,14 +284,12 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, return 0; } -#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(TX_CMD_FLG_MH_PAD) - int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr; - struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; + struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_txq *txq; dma_addr_t tb0_phys, tb1_phys, scratch_phys; @@ -345,9 +343,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[txq->write_ptr].meta; out_meta->flags = 0; @@ -361,9 +356,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len - IWL_FIRST_TB_SIZE; tb1_len = ALIGN(len, 4); - /* Tell NIC about any 2-byte padding after MAC header */ - if (tb1_len != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; /* * The first TB points to bi-directional DMA data, we'll From cefe13af25275eabc6d2ad4f6b67ee7b06f94c5f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 24 Jan 2017 15:50:35 +0200 Subject: [PATCH 123/201] iwlwifi: pcie: rewrite TFD creation Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 215 +++++++----------- 1 file changed, 82 insertions(+), 133 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 67af73ef7d0d4..4717440bc7f99 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -119,11 +119,10 @@ static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, struct iwl_cmd_meta *meta, - struct iwl_txq *txq, int index) + struct iwl_tfh_tfd *tfd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i, num_tbs; - struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); /* Sanity check on number of chunks */ num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); @@ -152,6 +151,8 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and * idx is bounded by n_window */ @@ -163,7 +164,8 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) /* We have only q->n_window txq->entries, but we use * TFD_QUEUE_SIZE_MAX tfds */ - iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, txq, rd_ptr); + iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, + iwl_pcie_get_tfd(trans_pcie, txq, rd_ptr)); /* free SKB */ if (txq->entries) { @@ -182,79 +184,89 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) } } -static inline void iwl_pcie_gen2_set_tb(struct iwl_trans *trans, void *tfd, - u8 idx, dma_addr_t addr, u16 len) -{ - struct iwl_tfh_tfd *tfd_fh = (void *)tfd; - struct iwl_tfh_tb *tb = &tfd_fh->tbs[idx]; - - put_unaligned_le64(addr, &tb->addr); - tb->tb_len = cpu_to_le16(len); - - tfd_fh->num_tbs = cpu_to_le16(idx + 1); -} - -int iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, - dma_addr_t addr, u16 len, bool reset) +static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, + struct iwl_tfh_tfd *tfd, dma_addr_t addr, + u16 len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - void *tfd; - u32 num_tbs; - - tfd = txq->tfds + trans_pcie->tfd_size * txq->write_ptr; - - if (reset) - memset(tfd, 0, trans_pcie->tfd_size); - - num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); + int idx = iwl_pcie_gen2_get_num_tbs(trans, tfd); + struct iwl_tfh_tb *tb = &tfd->tbs[idx]; /* Each TFD can point to a maximum max_tbs Tx buffers */ - if (num_tbs >= trans_pcie->max_tbs) { + if (tfd->num_tbs >= trans_pcie->max_tbs) { IWL_ERR(trans, "Error can not send more than %d chunks\n", trans_pcie->max_tbs); return -EINVAL; } - if (WARN(addr & ~IWL_TX_DMA_MASK, - "Unaligned address = %llx\n", (unsigned long long)addr)) - return -EINVAL; + put_unaligned_le64(addr, &tb->addr); + tb->tb_len = cpu_to_le16(len); - iwl_pcie_gen2_set_tb(trans, tfd, num_tbs, addr, len); + tfd->num_tbs = cpu_to_le16(idx + 1); - return num_tbs; + return idx; } -static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len) +static +struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, + struct iwl_txq *txq, + struct iwl_device_cmd *dev_cmd, + struct sk_buff *skb, + struct iwl_cmd_meta *out_meta) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 tb2_len; - int i; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfh_tfd *tfd = + iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + dma_addr_t tb_phys; + int i, len, tb1_len, tb2_len, hdr_len; + void *tb1_addr; + + memset(tfd, 0, sizeof(*tfd)); + + tb_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); + /* The first TB points to bi-directional DMA data */ + memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + IWL_FIRST_TB_SIZE); + + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE); + + /* there must be data left over for TB1 or this code must be changed */ + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen2) < IWL_FIRST_TB_SIZE); /* - * Set up TFD's third entry to point directly to remainder - * of skb's head, if any + * The second TB (tb1) points to the remainder of the TX command + * and the 802.11 header - dword aligned size + * (This calculation modifies the TX command, so do it before the + * setup of the first TB) */ + len = sizeof(struct iwl_tx_cmd_gen2) + sizeof(struct iwl_cmd_header) + + ieee80211_hdrlen(hdr->frame_control) - IWL_FIRST_TB_SIZE; + + tb1_len = ALIGN(len, 4); + + /* map the data for TB1 */ + tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; + tb_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + goto out_err; + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len); + + /* set up TFD's third entry to point to remainder of skb's head */ + hdr_len = ieee80211_hdrlen(hdr->frame_control); tb2_len = skb_headlen(skb) - hdr_len; if (tb2_len > 0) { - dma_addr_t tb2_phys = dma_map_single(trans->dev, - skb->data + hdr_len, - tb2_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) { - iwl_pcie_gen2_tfd_unmap(trans, out_meta, txq, - txq->write_ptr); - return -EINVAL; - } - iwl_pcie_gen2_build_tfd(trans, txq, tb2_phys, tb2_len, false); + tb_phys = dma_map_single(trans->dev, skb->data + hdr_len, + tb2_len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + goto out_err; + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len); } /* set up the remaining entries to point to the data */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - dma_addr_t tb_phys; int tb_idx; if (!skb_frag_size(frag)) @@ -263,44 +275,35 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, tb_phys = skb_frag_dma_map(trans->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { - iwl_pcie_gen2_tfd_unmap(trans, out_meta, txq, - txq->write_ptr); - return -EINVAL; - } - tb_idx = iwl_pcie_gen2_build_tfd(trans, txq, tb_phys, - skb_frag_size(frag), false); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + goto out_err; + tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, + skb_frag_size(frag)); out_meta->tbs |= BIT(tb_idx); } - trace_iwlwifi_dev_tx(trans->dev, skb, - iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), - trans_pcie->tfd_size, - &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, + trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, + IWL_FIRST_TB_SIZE + tb1_len, skb->data + hdr_len, tb2_len); - trace_iwlwifi_dev_tx_data(trans->dev, skb, - hdr_len, skb->len - hdr_len); - return 0; + trace_iwlwifi_dev_tx_data(trans->dev, skb, hdr_len, + skb->len - hdr_len); + + return tfd; + +out_err: + iwl_pcie_gen2_tfd_unmap(trans, out_meta, tfd); + return NULL; } int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct ieee80211_hdr *hdr; struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; - struct iwl_txq *txq; - dma_addr_t tb0_phys, tb1_phys, scratch_phys; - void *tb1_addr; + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; void *tfd; - u16 len, tb1_len; - __le16 fc; - u8 hdr_len; - u16 wifi_seq; - - txq = &trans_pcie->txq[txq_id]; if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), "TX on unused queue %d\n", txq_id)) @@ -311,26 +314,8 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, __skb_linearize(skb)) return -ENOMEM; - /* mac80211 always puts the full header into the SKB's head, - * so there's no need to check if it's readable there - */ - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - hdr_len = ieee80211_hdrlen(fc); - spin_lock(&txq->lock); - /* In AGG mode, the index in the ring must correspond to the WiFi - * sequence number. This is a HW requirements to help the SCD to parse - * the BA. - * Check here that the packets are in the right place on the ring. - */ - wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - WARN_ONCE(txq->ampdu && - (wifi_seq & 0xff) != txq->write_ptr, - "Q: %d WiFi Seq %d tfdNum %d", - txq_id, wifi_seq, txq->write_ptr); - /* Set up driver data for this TFD */ txq->entries[txq->write_ptr].skb = skb; txq->entries[txq->write_ptr].cmd = dev_cmd; @@ -339,49 +324,16 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | INDEX_TO_SEQ(txq->write_ptr))); - tb0_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); - scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[txq->write_ptr].meta; out_meta->flags = 0; - /* - * The second TB (tb1) points to the remainder of the TX command - * and the 802.11 header - dword aligned size - * (This calculation modifies the TX command, so do it before the - * setup of the first TB) - */ - len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + - hdr_len - IWL_FIRST_TB_SIZE; - tb1_len = ALIGN(len, 4); - - /* - * The first TB points to bi-directional DMA data, we'll - * memcpy the data into it later. - */ - iwl_pcie_gen2_build_tfd(trans, txq, tb0_phys, IWL_FIRST_TB_SIZE, true); - - /* there must be data left over for TB1 or this code must be changed */ - BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE); - - /* map the data for TB1 */ - tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; - tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(trans->dev, tb1_phys))) - goto out_err; - iwl_pcie_gen2_build_tfd(trans, txq, tb1_phys, tb1_len, false); - - if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len, - out_meta, dev_cmd, tb1_len))) - goto out_err; - - /* building the A-MSDU might have changed this data, so memcpy it now */ - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, - IWL_FIRST_TB_SIZE); + tfd = iwl_pcie_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta); + if (!tfd) { + spin_unlock(&txq->lock); + return -1; + } - tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_gen2_update_byte_tbl(trans, txq, le16_to_cpu(tx_cmd->len), iwl_pcie_gen2_get_num_tbs(trans, tfd)); @@ -417,9 +369,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, */ spin_unlock(&txq->lock); return 0; -out_err: - spin_unlock(&txq->lock); - return -1; } /* From ca60da2eb41641183c9a1b85a7de26f1327ba356 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 8 Dec 2016 13:22:55 +0200 Subject: [PATCH 124/201] iwlwifi: pcie: support host commands in new transport Code is basically the same, with a cleanups of old narrow host command, ampg workarounds, some cosmetic stuff, and usage of TFH functions when accessing TFD queues. This enables also the cleanup of iwl_pcie_tfd_set_tb() since now it won't be called anywhere in the a000 data path Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 2 + .../net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 386 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 24 +- 4 files changed, 396 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 912d475ed2926..2266f3aa67aae 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -778,5 +778,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); +int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index e1610241be07c..16a057398de22 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2918,7 +2918,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .start_fw = iwl_trans_pcie_gen2_start_fw, .stop_device = iwl_trans_pcie_stop_device, - .send_cmd = iwl_trans_pcie_send_hcmd, + .send_cmd = iwl_trans_pcie_gen2_send_hcmd, .tx = iwl_trans_pcie_gen2_tx, .reclaim = iwl_trans_pcie_reclaim, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 4717440bc7f99..af5b97c82c5ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -48,6 +48,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#include #include "iwl-debug.h" #include "iwl-csr.h" @@ -371,6 +372,391 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, return 0; } +/*************** HOST COMMAND QUEUE FUNCTIONS *****/ + +/* + * iwl_pcie_gen2_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a pointer to the ucode command structure + * + * The function returns < 0 values to indicate the operation + * failed. On success, it returns the index (>= 0) of command in the + * command queue. + */ +static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; + unsigned long flags; + void *dup_buf = NULL; + dma_addr_t phys_addr; + int idx, i, cmd_pos; + u16 copy_size, cmd_size, tb0_size; + bool had_nocopy = false; + u8 group_id = iwl_cmd_groupid(cmd->id); + const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; + u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; + struct iwl_tfh_tfd *tfd = + iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + + memset(tfd, 0, sizeof(*tfd)); + + copy_size = sizeof(struct iwl_cmd_header_wide); + cmd_size = sizeof(struct iwl_cmd_header_wide); + + for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { + cmddata[i] = cmd->data[i]; + cmdlen[i] = cmd->len[i]; + + if (!cmd->len[i]) + continue; + + /* need at least IWL_FIRST_TB_SIZE copied */ + if (copy_size < IWL_FIRST_TB_SIZE) { + int copy = IWL_FIRST_TB_SIZE - copy_size; + + if (copy > cmdlen[i]) + copy = cmdlen[i]; + cmdlen[i] -= copy; + cmddata[i] += copy; + copy_size += copy; + } + + if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { + had_nocopy = true; + if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { + idx = -EINVAL; + goto free_dup_buf; + } + } else if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) { + /* + * This is also a chunk that isn't copied + * to the static buffer so set had_nocopy. + */ + had_nocopy = true; + + /* only allowed once */ + if (WARN_ON(dup_buf)) { + idx = -EINVAL; + goto free_dup_buf; + } + + dup_buf = kmemdup(cmddata[i], cmdlen[i], + GFP_ATOMIC); + if (!dup_buf) + return -ENOMEM; + } else { + /* NOCOPY must not be followed by normal! */ + if (WARN_ON(had_nocopy)) { + idx = -EINVAL; + goto free_dup_buf; + } + copy_size += cmdlen[i]; + } + cmd_size += cmd->len[i]; + } + + /* + * If any of the command structures end up being larger than the + * TFD_MAX_PAYLOAD_SIZE and they aren't dynamically allocated into + * separate TFDs, then we will need to increase the size of the buffers + */ + if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE, + "Command %s (%#x) is too large (%d bytes)\n", + iwl_get_cmd_string(trans, cmd->id), cmd->id, copy_size)) { + idx = -EINVAL; + goto free_dup_buf; + } + + spin_lock_bh(&txq->lock); + + if (iwl_queue_space(txq) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_bh(&txq->lock); + + IWL_ERR(trans, "No space in command queue\n"); + iwl_op_mode_cmd_queue_full(trans->op_mode); + idx = -ENOSPC; + goto free_dup_buf; + } + + idx = get_cmd_index(txq, txq->write_ptr); + out_cmd = txq->entries[idx].cmd; + out_meta = &txq->entries[idx].meta; + + /* re-initialize to NULL */ + memset(out_meta, 0, sizeof(*out_meta)); + if (cmd->flags & CMD_WANT_SKB) + out_meta->source = cmd; + + /* set up the header */ + out_cmd->hdr_wide.cmd = iwl_cmd_opcode(cmd->id); + out_cmd->hdr_wide.group_id = group_id; + out_cmd->hdr_wide.version = iwl_cmd_version(cmd->id); + out_cmd->hdr_wide.length = + cpu_to_le16(cmd_size - sizeof(struct iwl_cmd_header_wide)); + out_cmd->hdr_wide.reserved = 0; + out_cmd->hdr_wide.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | + INDEX_TO_SEQ(txq->write_ptr)); + + cmd_pos = sizeof(struct iwl_cmd_header_wide); + copy_size = sizeof(struct iwl_cmd_header_wide); + + /* and copy the data that needs to be copied */ + for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { + int copy; + + if (!cmd->len[i]) + continue; + + /* copy everything if not nocopy/dup */ + if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | + IWL_HCMD_DFL_DUP))) { + copy = cmd->len[i]; + + memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); + cmd_pos += copy; + copy_size += copy; + continue; + } + + /* + * Otherwise we need at least IWL_FIRST_TB_SIZE copied + * in total (for bi-directional DMA), but copy up to what + * we can fit into the payload for debug dump purposes. + */ + copy = min_t(int, TFD_MAX_PAYLOAD_SIZE - cmd_pos, cmd->len[i]); + + memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy); + cmd_pos += copy; + + /* However, treat copy_size the proper way, we need it below */ + if (copy_size < IWL_FIRST_TB_SIZE) { + copy = IWL_FIRST_TB_SIZE - copy_size; + + if (copy > cmd->len[i]) + copy = cmd->len[i]; + copy_size += copy; + } + } + + IWL_DEBUG_HC(trans, + "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", + iwl_get_cmd_string(trans, cmd->id), group_id, + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + cmd_size, txq->write_ptr, idx, trans_pcie->cmd_queue); + + /* start the TFD with the minimum copy bytes */ + tb0_size = min_t(int, copy_size, IWL_FIRST_TB_SIZE); + memcpy(&txq->first_tb_bufs[idx], &out_cmd->hdr, tb0_size); + iwl_pcie_gen2_set_tb(trans, tfd, iwl_pcie_get_first_tb_dma(txq, idx), + tb0_size); + + /* map first command fragment, if any remains */ + if (copy_size > tb0_size) { + phys_addr = dma_map_single(trans->dev, + ((u8 *)&out_cmd->hdr) + tb0_size, + copy_size - tb0_size, + DMA_TO_DEVICE); + if (dma_mapping_error(trans->dev, phys_addr)) { + idx = -ENOMEM; + iwl_pcie_gen2_tfd_unmap(trans, out_meta, tfd); + goto out; + } + iwl_pcie_gen2_set_tb(trans, tfd, phys_addr, + copy_size - tb0_size); + } + + /* map the remaining (adjusted) nocopy/dup fragments */ + for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { + const void *data = cmddata[i]; + + if (!cmdlen[i]) + continue; + if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY | + IWL_HCMD_DFL_DUP))) + continue; + if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) + data = dup_buf; + phys_addr = dma_map_single(trans->dev, (void *)data, + cmdlen[i], DMA_TO_DEVICE); + if (dma_mapping_error(trans->dev, phys_addr)) { + idx = -ENOMEM; + iwl_pcie_gen2_tfd_unmap(trans, out_meta, tfd); + goto out; + } + iwl_pcie_gen2_set_tb(trans, tfd, phys_addr, cmdlen[i]); + } + + BUILD_BUG_ON(IWL_TFH_NUM_TBS > sizeof(out_meta->tbs) * BITS_PER_BYTE); + out_meta->flags = cmd->flags; + if (WARN_ON_ONCE(txq->entries[idx].free_buf)) + kzfree(txq->entries[idx].free_buf); + txq->entries[idx].free_buf = dup_buf; + + trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr_wide); + + /* start timer if queue currently empty */ + if (txq->read_ptr == txq->write_ptr && txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); + + spin_lock_irqsave(&trans_pcie->reg_lock, flags); + if (!(cmd->flags & CMD_SEND_IN_IDLE) && + !trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = true; + IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n"); + iwl_trans_ref(trans); + } + /* Increment and update queue's write index */ + txq->write_ptr = iwl_queue_inc_wrap(txq->write_ptr); + iwl_pcie_gen2_txq_inc_wr_ptr(trans, txq); + spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); + +out: + spin_unlock_bh(&txq->lock); +free_dup_buf: + if (idx < 0) + kfree(dup_buf); + return idx; +} + +#define HOST_COMPLETE_TIMEOUT (2 * HZ) + +static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + const char *cmd_str = iwl_get_cmd_string(trans, cmd->id); + int cmd_idx; + int ret; + + IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", cmd_str); + + if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status), + "Command %s: a command is already active!\n", cmd_str)) + return -EIO; + + IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", cmd_str); + + if (pm_runtime_suspended(&trans_pcie->pci_dev->dev)) { + ret = wait_event_timeout(trans_pcie->d0i3_waitq, + pm_runtime_active(&trans_pcie->pci_dev->dev), + msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT)); + if (!ret) { + IWL_ERR(trans, "Timeout exiting D0i3 before hcmd\n"); + return -ETIMEDOUT; + } + } + + cmd_idx = iwl_pcie_gen2_enqueue_hcmd(trans, cmd); + if (cmd_idx < 0) { + ret = cmd_idx; + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); + IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", + cmd_str, ret); + return ret; + } + + ret = wait_event_timeout(trans_pcie->wait_command_queue, + !test_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + + IWL_ERR(trans, "Error sending %s: time out after %dms.\n", + cmd_str, jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", + txq->read_ptr, txq->write_ptr); + + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); + IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", + cmd_str); + ret = -ETIMEDOUT; + + iwl_force_nmi(trans); + iwl_trans_fw_error(trans); + + goto cancel; + } + + if (test_bit(STATUS_FW_ERROR, &trans->status)) { + IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); + dump_stack(); + ret = -EIO; + goto cancel; + } + + if (!(cmd->flags & CMD_SEND_IN_RFKILL) && + test_bit(STATUS_RFKILL, &trans->status)) { + IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); + ret = -ERFKILL; + goto cancel; + } + + if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) { + IWL_ERR(trans, "Error: Response NULL in '%s'\n", cmd_str); + ret = -EIO; + goto cancel; + } + + return 0; + +cancel: + if (cmd->flags & CMD_WANT_SKB) { + /* + * Cancel the CMD_WANT_SKB flag for the cmd in the + * TX cmd queue. Otherwise in case the cmd comes + * in later, it will possibly set an invalid + * address (cmd->meta.source). + */ + trans_pcie->txq[trans_pcie->cmd_queue]. + entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; + } + + if (cmd->resp_pkt) { + iwl_free_resp(cmd); + cmd->resp_pkt = NULL; + } + + return ret; +} + +int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) +{ + if (!(cmd->flags & CMD_SEND_IN_RFKILL) && + test_bit(STATUS_RFKILL, &trans->status)) { + IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", + cmd->id); + return -ERFKILL; + } + + if (cmd->flags & CMD_ASYNC) { + int ret; + + /* An asynchronous command can not expect an SKB to be set. */ + if (WARN_ON(cmd->flags & CMD_WANT_SKB)) + return -EINVAL; + + ret = iwl_pcie_gen2_enqueue_hcmd(trans, cmd); + if (ret < 0) { + IWL_ERR(trans, + "Error sending %s: enqueue_hcmd failed: %d\n", + iwl_get_cmd_string(trans, cmd->id), ret); + return ret; + } + return 0; + } + + return iwl_pcie_gen2_send_hcmd_sync(trans, cmd); +} + /* * iwl_pcie_gen2_txq_unmap - Unmap any remaining DMA mappings and free skb's */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index d57310eaaef72..5af6eb98eb433 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -341,27 +341,17 @@ static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_trans *trans, static inline void iwl_pcie_tfd_set_tb(struct iwl_trans *trans, void *tfd, u8 idx, dma_addr_t addr, u16 len) { - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd_fh = (void *)tfd; - struct iwl_tfh_tb *tb = &tfd_fh->tbs[idx]; + struct iwl_tfd *tfd_fh = (void *)tfd; + struct iwl_tfd_tb *tb = &tfd_fh->tbs[idx]; - put_unaligned_le64(addr, &tb->addr); - tb->tb_len = cpu_to_le16(len); + u16 hi_n_len = len << 4; - tfd_fh->num_tbs = cpu_to_le16(idx + 1); - } else { - struct iwl_tfd *tfd_fh = (void *)tfd; - struct iwl_tfd_tb *tb = &tfd_fh->tbs[idx]; + put_unaligned_le32(addr, &tb->lo); + hi_n_len |= iwl_get_dma_hi_addr(addr); - u16 hi_n_len = len << 4; + tb->hi_n_len = cpu_to_le16(hi_n_len); - put_unaligned_le32(addr, &tb->lo); - hi_n_len |= iwl_get_dma_hi_addr(addr); - - tb->hi_n_len = cpu_to_le16(hi_n_len); - - tfd_fh->num_tbs = idx + 1; - } + tfd_fh->num_tbs = idx + 1; } static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_trans *trans, void *_tfd) From 4822929388df78c57f85bc4f8aca781e268da44f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 8 Dec 2016 12:05:58 +0200 Subject: [PATCH 125/201] iwlwifi: pcie: support new write pointer width In a000 devices we have 16 bytes for the TFD index and 16 for the queue, in order to support 512 queues. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index af5b97c82c5ea..e8eb112827954 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -109,7 +109,7 @@ static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, */ if (!txq->block) iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq->id << 8)); + txq->write_ptr | (txq->id << 16)); } static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, @@ -825,7 +825,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, txq->read_ptr = (ssn & 0xff); txq->write_ptr = (ssn & 0xff); iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (cmd->scd_queue << 8)); + (ssn & 0xff) | (cmd->scd_queue << 16)); IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d WrPtr: %d\n", cmd->scd_queue, ssn & 0xff); From 43e9cdc268cbc462d88d6b48dbc36b34429b782b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 29 Nov 2016 13:19:25 +0200 Subject: [PATCH 126/201] iwlwifi: pcie: remove block and freeze operations from new transport New transport will be used only by op modes that supports buffer station offload - hence those will never be called. Clean it up. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/pcie/trans.c | 3 --- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 22 +++---------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 16a057398de22..d39ca944f4840 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2925,9 +2925,6 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, .txq_free = iwl_trans_pcie_dyn_txq_free, - - .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, - .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index e8eb112827954..2019ccda31c4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -107,9 +107,7 @@ static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, * if not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ - if (!txq->block) - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq->id << 16)); + iwl_write32(trans, HBUS_TARG_WRPTR, txq->write_ptr | (txq->id << 16)); } static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, @@ -341,19 +339,8 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (txq->read_ptr == txq->write_ptr) { - if (txq->wd_timeout) { - /* - * If the TXQ is active, then set the timer, if not, - * set the timer in remainder so that the timer will - * be armed with the right value when the station will - * wake up. - */ - if (!txq->frozen) - mod_timer(&txq->stuck_timer, - jiffies + txq->wd_timeout); - else - txq->frozen_expiry_remainder = txq->wd_timeout; - } + if (txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", txq->id); iwl_trans_ref(trans); } @@ -843,9 +830,6 @@ void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - trans_pcie->txq[queue].frozen_expiry_remainder = 0; - trans_pcie->txq[queue].frozen = false; - /* * Upon HW Rfkill - we stop the device, and then stop the queues * in the op_mode. Just for the sake of the simplicity of the op_mode, From b2a3b1c1044cb686d3b975fa36e42f477b2aa386 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 11 Dec 2016 11:36:38 +0200 Subject: [PATCH 127/201] iwlwifi: pcie: prepare for dynamic queue allocation In a000 transport we will allocate queues dynamically. Right now queue are allocated as one big chunk of memory and accessed as such. The dynamic allocation of the queues will require accessing the queues as pointers. In order to keep simplicity of pre-a000 tx queues handling, keep allocating and freeing the memory in the same style, but move to access the queues in the various functions as individual pointers. Dynamic allocation for the a000 devices will be in a separate patch. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/ctxt-info.c | 2 +- .../wireless/intel/iwlwifi/pcie/internal.h | 3 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 12 +-- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 14 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 81 ++++++++++--------- 6 files changed, 58 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 312ee0481ec57..854d61888f4df 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -235,7 +235,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, /* initialize TX command queue */ ctxt_info->hcmd_cfg.cmd_queue_addr = - cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue].dma_addr); + cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue]->dma_addr); ctxt_info->hcmd_cfg.cmd_queue_size = TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 2266f3aa67aae..cdc2b0a938a1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -411,7 +411,8 @@ struct iwl_trans_pcie { struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr kw; - struct iwl_txq *txq; + struct iwl_txq *txq_memory; + struct iwl_txq *txq[IWL_MAX_HW_QUEUES]; unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index c6178d36698c2..0338c5f41ce6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1094,7 +1094,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, bool emergency) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; bool page_stolen = false; int max_len = PAGE_SIZE << trans_pcie->rx_page_order; u32 offset = 0; @@ -1420,7 +1420,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) local_bh_enable(); for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) - del_timer(&trans_pcie->txq[i].stuck_timer); + del_timer(&trans_pcie->txq[i]->stuck_timer); clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d39ca944f4840..ccc9280d845af 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1983,7 +1983,7 @@ static void iwl_trans_pcie_freeze_txq_timer(struct iwl_trans *trans, int queue; for_each_set_bit(queue, &txqs, BITS_PER_LONG) { - struct iwl_txq *txq = &trans_pcie->txq[queue]; + struct iwl_txq *txq = trans_pcie->txq[queue]; unsigned long now; spin_lock_bh(&txq->lock); @@ -2035,7 +2035,7 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) int i; for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { - struct iwl_txq *txq = &trans_pcie->txq[i]; + struct iwl_txq *txq = trans_pcie->txq[i]; if (i == trans_pcie->cmd_queue) continue; @@ -2108,7 +2108,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) continue; IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); - txq = &trans_pcie->txq[cnt]; + txq = trans_pcie->txq[cnt]; wr_ptr = ACCESS_ONCE(txq->write_ptr); while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && @@ -2299,7 +2299,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, bufsz = sizeof(char) * 75 * trans->cfg->base_params->num_of_queues; - if (!trans_pcie->txq) + if (!trans_pcie->txq_memory) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -2307,7 +2307,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, return -ENOMEM; for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - txq = &trans_pcie->txq[cnt]; + txq = trans_pcie->txq[cnt]; pos += scnprintf(buf + pos, bufsz - pos, "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d frozen=%d%s\n", cnt, txq->read_ptr, txq->write_ptr, @@ -2724,7 +2724,7 @@ static struct iwl_trans_dump_data { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_fw_error_dump_data *data; - struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_fw_error_dump_txcmd *txcmd; struct iwl_trans_dump_data *dump_data; u32 len, num_rbs; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 2019ccda31c4c..b938a6a3b1692 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -301,7 +301,7 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; void *tfd; if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), @@ -374,7 +374,7 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_device_cmd *out_cmd; struct iwl_cmd_meta *out_meta; unsigned long flags; @@ -617,6 +617,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); const char *cmd_str = iwl_get_cmd_string(trans, cmd->id); + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; int cmd_idx; int ret; @@ -653,8 +654,6 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, &trans->status), HOST_COMPLETE_TIMEOUT); if (!ret) { - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; - IWL_ERR(trans, "Error sending %s: time out after %dms.\n", cmd_str, jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); @@ -702,8 +701,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, * in later, it will possibly set an invalid * address (cmd->meta.source). */ - trans_pcie->txq[trans_pcie->cmd_queue]. - entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; + txq->entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; } if (cmd->resp_pkt) { @@ -750,7 +748,7 @@ int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; spin_lock_bh(&txq->lock); while (txq->write_ptr != txq->read_ptr) { @@ -789,7 +787,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, unsigned int timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[cmd->scd_queue]; + struct iwl_txq *txq = trans_pcie->txq[cmd->scd_queue]; struct iwl_host_cmd hcmd = { .id = cmd_id, .len = { sizeof(*cmd) }, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 5af6eb98eb433..9ea92ac3920e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -298,12 +298,12 @@ void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans) int i; for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { - struct iwl_txq *txq = &trans_pcie->txq[i]; + struct iwl_txq *txq = trans_pcie->txq[i]; spin_lock_bh(&txq->lock); - if (trans_pcie->txq[i].need_update) { + if (txq->need_update) { iwl_pcie_txq_inc_wr_ptr(trans, txq); - trans_pcie->txq[i].need_update = false; + txq->need_update = false; } spin_unlock_bh(&txq->lock); } @@ -622,7 +622,7 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; spin_lock_bh(&txq->lock); while (txq->write_ptr != txq->read_ptr) { @@ -678,7 +678,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; struct device *dev = trans->dev; int i; @@ -780,7 +780,7 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; if (trans->cfg->use_tfh) iwl_write_direct64(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), @@ -860,7 +860,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans) memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); /* This can happen: start_hw, stop_device */ - if (!trans_pcie->txq) + if (!trans_pcie->txq_memory) return 0; /* Unmap DMA from host system and free skb's */ @@ -884,14 +884,17 @@ void iwl_pcie_tx_free(struct iwl_trans *trans) memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); /* Tx queues */ - if (trans_pcie->txq) { + if (trans_pcie->txq_memory) { for (txq_id = 0; - txq_id < trans->cfg->base_params->num_of_queues; txq_id++) + txq_id < trans->cfg->base_params->num_of_queues; + txq_id++) { iwl_pcie_txq_free(trans, txq_id); + trans_pcie->txq[txq_id] = NULL; + } } - kfree(trans_pcie->txq); - trans_pcie->txq = NULL; + kfree(trans_pcie->txq_memory); + trans_pcie->txq_memory = NULL; iwl_pcie_free_dma_ptr(trans, &trans_pcie->kw); @@ -913,7 +916,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) /*It is not allowed to alloc twice, so warn when this happens. * We cannot rely on the previous allocation, so free and fail */ - if (WARN_ON(trans_pcie->txq)) { + if (WARN_ON(trans_pcie->txq_memory)) { ret = -EINVAL; goto error; } @@ -932,9 +935,9 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) goto error; } - trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues, - sizeof(struct iwl_txq), GFP_KERNEL); - if (!trans_pcie->txq) { + trans_pcie->txq_memory = kcalloc(trans->cfg->base_params->num_of_queues, + sizeof(struct iwl_txq), GFP_KERNEL); + if (!trans_pcie->txq_memory) { IWL_ERR(trans, "Not enough memory for txq\n"); ret = -ENOMEM; goto error; @@ -945,8 +948,9 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) txq_id++) { slots_num = (txq_id == trans_pcie->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_pcie_txq_alloc(trans, &trans_pcie->txq[txq_id], - slots_num, txq_id); + trans_pcie->txq[txq_id] = &trans_pcie->txq_memory[txq_id]; + ret = iwl_pcie_txq_alloc(trans, trans_pcie->txq[txq_id], + slots_num, txq_id); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); goto error; @@ -968,7 +972,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) int txq_id, slots_num; bool alloc = false; - if (!trans_pcie->txq) { + if (!trans_pcie->txq_memory) { ret = iwl_pcie_tx_alloc(trans); if (ret) goto error; @@ -991,8 +995,8 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) txq_id++) { slots_num = (txq_id == trans_pcie->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_pcie_txq_init(trans, &trans_pcie->txq[txq_id], - slots_num, txq_id); + ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], + slots_num, txq_id); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; @@ -1005,7 +1009,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) * Circular buffer (TFD queue in DRAM) physical base address */ iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), - trans_pcie->txq[txq_id].dma_addr >> 8); + trans_pcie->txq[txq_id]->dma_addr >> 8); } iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); @@ -1028,7 +1032,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) int txq_id, slots_num; bool alloc = false; - if (!trans_pcie->txq) { + if (!trans_pcie->txq_memory) { /* TODO: change this when moving to new TX alloc model */ ret = iwl_pcie_tx_alloc(trans); if (ret) @@ -1049,7 +1053,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) txq_id++) { slots_num = (txq_id == trans_pcie->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_pcie_txq_init(trans, &trans_pcie->txq[txq_id], + ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], slots_num, txq_id); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); @@ -1095,7 +1099,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; int tfd_num = ssn & (TFD_QUEUE_SIZE_MAX - 1); int last_to_free; @@ -1252,7 +1256,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; unsigned long flags; int nfreed = 0; @@ -1319,7 +1323,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, unsigned int wdg_timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; int fifo = -1; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) @@ -1412,7 +1416,7 @@ void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id, bool shared_mode) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[txq_id]; + struct iwl_txq *txq = trans_pcie->txq[txq_id]; txq->ampdu = !shared_mode; } @@ -1425,8 +1429,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, SCD_TX_STTS_QUEUE_OFFSET(txq_id); static const u32 zero_val[4] = {}; - trans_pcie->txq[txq_id].frozen_expiry_remainder = 0; - trans_pcie->txq[txq_id].frozen = false; + trans_pcie->txq[txq_id]->frozen_expiry_remainder = 0; + trans_pcie->txq[txq_id]->frozen = false; /* * Upon HW Rfkill - we stop the device, and then stop the queues @@ -1448,7 +1452,7 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, } iwl_pcie_txq_unmap(trans, txq_id); - trans_pcie->txq[txq_id].ampdu = false; + trans_pcie->txq[txq_id]->ampdu = false; IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } @@ -1468,7 +1472,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_device_cmd *out_cmd; struct iwl_cmd_meta *out_meta; unsigned long flags; @@ -1753,16 +1757,15 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced * in the queue management code. */ if (WARN(txq_id != trans_pcie->cmd_queue, "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n", - txq_id, trans_pcie->cmd_queue, sequence, - trans_pcie->txq[trans_pcie->cmd_queue].read_ptr, - trans_pcie->txq[trans_pcie->cmd_queue].write_ptr)) { + txq_id, trans_pcie->cmd_queue, sequence, txq->read_ptr, + txq->write_ptr)) { iwl_print_hex_error(trans, pkt, 32); return; } @@ -1846,6 +1849,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; int cmd_idx; int ret; @@ -1886,8 +1890,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, &trans->status), HOST_COMPLETE_TIMEOUT); if (!ret) { - struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; - IWL_ERR(trans, "Error sending %s: time out after %dms.\n", iwl_get_cmd_string(trans, cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); @@ -1938,8 +1940,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, * in later, it will possibly set an invalid * address (cmd->meta.source). */ - trans_pcie->txq[trans_pcie->cmd_queue]. - entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; + txq->entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; } if (cmd->resp_pkt) { @@ -2293,7 +2294,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, u16 wifi_seq; bool amsdu; - txq = &trans_pcie->txq[txq_id]; + txq = trans_pcie->txq[txq_id]; if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), "TX on unused queue %d\n", txq_id)) From 77c09bc87278d8ccf224c4177e7168022cdd92a9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 12 Dec 2016 12:48:48 +0200 Subject: [PATCH 128/201] iwlwifi: pcie: introduce new stop_device This function is basically the same as gen1, except for clean ups of old devices configuration that are never used in a000 configuration. It will also help with refactoring rf_kill later on. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 5 + .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 147 ++++++++++++++++++ .../net/wireless/intel/iwlwifi/pcie/trans.c | 18 +-- 3 files changed, 161 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cdc2b0a938a1d..bb7b25976e90b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -767,6 +767,8 @@ void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); +int iwl_pcie_apm_stop_master(struct iwl_trans *trans); +void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -781,5 +783,8 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); +void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, + bool low_power); +void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 302310dfef9ee..4d5d35501fdcc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -111,6 +111,153 @@ static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) return 0; } +static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) +{ + IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); + + if (op_mode_leave) { + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + iwl_pcie_gen2_apm_init(trans); + + /* inform ME that we are leaving */ + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE | + CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(1); + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + mdelay(5); + } + + clear_bit(STATUS_DEVICE_ENABLED, &trans->status); + + /* Stop device's DMA activity */ + iwl_pcie_apm_stop_master(trans); + + /* Reset the entire device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(1000, 2000); + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); +} + +void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool hw_rfkill, was_hw_rfkill; + + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->is_down) + return; + + trans_pcie->is_down = true; + + was_hw_rfkill = iwl_is_rfkill_set(trans); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(trans); + + /* device going down, Stop using ICT table */ + iwl_pcie_disable_ict(trans); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { + IWL_DEBUG_INFO(trans, + "DEVICE_ENABLED bit was set and is now cleared\n"); + iwl_pcie_tx_stop(trans); + iwl_pcie_rx_stop(trans); + } + + iwl_pcie_ctxt_info_free_paging(trans); + iwl_pcie_ctxt_info_free(trans); + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_pcie_gen2_apm_stop(trans, false); + + /* stop and reset the on-board processor */ + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(1000, 2000); + + /* + * Upon stop, the IVAR table gets erased, so msi-x won't + * work. This causes a bug in RF-KILL flows, since the interrupt + * that enables radio won't fire on the correct irq, and the + * driver won't be able to handle the interrupt. + * Configure the IVAR table again after reset. + */ + iwl_pcie_conf_msix_hw(trans_pcie); + + /* + * Upon stop, the APM issues an interrupt if HW RF kill is set. + * This is a bug in certain verions of the hardware. + * Certain devices also keep sending HW RF kill interrupt all + * the time, unless the interrupt is ACKed even if the interrupt + * should be masked. Re-ACK all the interrupts here. + */ + iwl_disable_interrupts(trans); + + /* clear all status bits */ + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); + clear_bit(STATUS_INT_ENABLED, &trans->status); + clear_bit(STATUS_TPOWER_PMI, &trans->status); + clear_bit(STATUS_RFKILL, &trans->status); + + /* + * Even if we stop the HW, we still want the RF kill + * interrupt + */ + iwl_enable_rfkill_int(trans); + + /* + * Check again since the RF kill state may have changed while + * all the interrupts were disabled, in this case we couldn't + * receive the RF kill interrupt and update the state in the + * op_mode. + * Don't call the op_mode if the rkfill state hasn't changed. + * This allows the op_mode to call stop_device from the rfkill + * notification without endless recursion. Under very rare + * circumstances, we might have a small recursion if the rfkill + * state changed exactly now while we were called from stop_device. + * This is very unlikely but can happen and is supported. + */ + hw_rfkill = iwl_is_rfkill_set(trans); + if (hw_rfkill) + set_bit(STATUS_RFKILL, &trans->status); + else + clear_bit(STATUS_RFKILL, &trans->status); + if (hw_rfkill != was_hw_rfkill) + iwl_trans_pcie_rf_kill(trans, hw_rfkill); + + /* re-take ownership to prevent other users from stealing the device */ + iwl_pcie_prepare_card_hw(trans); +} + +void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + mutex_lock(&trans_pcie->mutex); + _iwl_trans_pcie_gen2_stop_device(trans, low_power); + mutex_unlock(&trans_pcie->mutex); +} + static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index ccc9280d845af..6a565d35f0715 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -80,7 +80,6 @@ #include "iwl-prph.h" #include "iwl-scd.h" #include "iwl-agn-hw.h" -#include "iwl-context-info.h" #include "iwl-fw-error-dump.h" #include "internal.h" #include "iwl-fh.h" @@ -449,7 +448,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) ~SHR_APMG_XTAL_CFG_XTAL_ON_REQ); } -static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) +int iwl_pcie_apm_stop_master(struct iwl_trans *trans) { int ret = 0; @@ -1126,7 +1125,7 @@ static void iwl_pcie_map_rx_causes(struct iwl_trans *trans) iwl_write8(trans, CSR_MSIX_RX_IVAR(1), val); } -static void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) +void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) { struct iwl_trans *trans = trans_pcie->trans; @@ -1213,9 +1212,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) } } - iwl_pcie_ctxt_info_free_paging(trans); - iwl_pcie_ctxt_info_free(trans); - /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -1405,8 +1401,12 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) lockdep_assert_held(&trans_pcie->mutex); - if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - _iwl_trans_pcie_stop_device(trans, true); + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) { + if (trans->cfg->gen2) + _iwl_trans_pcie_gen2_stop_device(trans, true); + else + _iwl_trans_pcie_stop_device(trans, true); + } } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, @@ -2916,7 +2916,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .start_hw = iwl_trans_pcie_start_hw, .fw_alive = iwl_trans_pcie_gen2_fw_alive, .start_fw = iwl_trans_pcie_gen2_start_fw, - .stop_device = iwl_trans_pcie_stop_device, + .stop_device = iwl_trans_pcie_gen2_stop_device, .send_cmd = iwl_trans_pcie_gen2_send_hcmd, From 13a3a39052aa42ed7e8ca2540366169584ae321f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 29 Nov 2016 13:49:59 +0200 Subject: [PATCH 129/201] iwlwifi: pcie: alloc queues dynamically Change queue allocation to be dynamic. On transport init only the command queue is being allocated. Other queues are allocated on demand. This is due to the huge amount of queues we will soon enable (512) and as a preparation for TX Virtual Queue Manager feature (TVQM), where firmware will assign the actual queue number on demand. This includes also allocation of the byte count table per queue and not as a contiguous chunk of memory. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 13 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 5 +- .../wireless/intel/iwlwifi/pcie/trans-gen2.c | 2 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 5 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 179 ++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 68 ++----- 6 files changed, 199 insertions(+), 73 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index bb7b25976e90b..405ae3799f5e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -241,6 +241,7 @@ struct iwl_pcie_first_tb_buf { * @wd_timeout: queue watchdog timeout (jiffies) - per queue * @frozen: tx stuck queue timer is frozen * @frozen_expiry_remainder: remember how long until the timer fires + * @bc_tbl: byte count table of the queue (relevant only for gen2 transport) * @write_ptr: 1-st empty entry (index) host_w * @read_ptr: last used entry (index) host_r * @dma_addr: physical addr for BD's @@ -280,6 +281,7 @@ struct iwl_txq { int block; unsigned long wd_timeout; struct sk_buff_head overflow_q; + struct iwl_dma_ptr bc_tbl; int write_ptr; int read_ptr; @@ -769,6 +771,13 @@ void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); int iwl_pcie_apm_stop_master(struct iwl_trans *trans); void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); +int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, + int slots_num, u32 txq_id); +int iwl_pcie_txq_alloc(struct iwl_trans *trans, + struct iwl_txq *txq, int slots_num, u32 txq_id); +int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr, size_t size); +void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -786,5 +795,7 @@ int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power); void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power); - +void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id); +void iwl_pcie_gen2_tx_free(struct iwl_trans *trans); +void iwl_pcie_gen2_tx_stop(struct iwl_trans *trans); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 0338c5f41ce6a..f98f2d2b8a1b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1419,8 +1419,11 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) iwl_trans_fw_error(trans); local_bh_enable(); - for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { + if (!trans_pcie->txq[i]) + continue; del_timer(&trans_pcie->txq[i]->stuck_timer); + } clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 4d5d35501fdcc..ef8f563a48d94 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -177,7 +177,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); - iwl_pcie_tx_stop(trans); + iwl_pcie_gen2_tx_stop(trans); iwl_pcie_rx_stop(trans); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 6a565d35f0715..ed1034e58cb42 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1813,7 +1813,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) iwl_pcie_synchronize_irqs(trans); - iwl_pcie_tx_free(trans); + if (trans->cfg->gen2) + iwl_pcie_gen2_tx_free(trans); + else + iwl_pcie_tx_free(trans); iwl_pcie_rx_free(trans); if (trans_pcie->msix_enabled) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index b938a6a3b1692..446e837613a57 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -56,22 +56,42 @@ #include "internal.h" #include "mvm/fw-api.h" + /* + * iwl_pcie_gen2_tx_stop - Stop all Tx DMA channels + */ +void iwl_pcie_gen2_tx_stop(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int txq_id; + + /* + * This function can be called before the op_mode disabled the + * queues. This happens when we have an rfkill interrupt. + * Since we stop Tx altogether - mark the queues as stopped. + */ + memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + + /* Unmap DMA from host system and free skb's */ + for (txq_id = 0; txq_id < ARRAY_SIZE(trans_pcie->txq); txq_id++) { + if (!trans_pcie->txq[txq_id]) + continue; + iwl_pcie_gen2_txq_unmap(trans, txq_id); + } +} + /* * iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array */ -static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, - struct iwl_txq *txq, u16 byte_cnt, - int num_tbs) +static void iwl_pcie_gen2_update_byte_tbl(struct iwl_txq *txq, u16 byte_cnt, + int num_tbs) { - struct iwlagn_scd_bc_tbl *scd_bc_tbl; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwlagn_scd_bc_tbl *scd_bc_tbl = txq->bc_tbl.addr; int write_ptr = txq->write_ptr; u8 filled_tfd_size, num_fetch_chunks; u16 len = byte_cnt; __le16 bc_ent; - scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; - len = DIV_ROUND_UP(len, 4); if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) @@ -90,7 +110,7 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12)); - scd_bc_tbl[txq->id].tfd_offset[write_ptr] = bc_ent; + scd_bc_tbl->tfd_offset[write_ptr] = bc_ent; } /* @@ -192,7 +212,7 @@ static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, struct iwl_tfh_tb *tb = &tfd->tbs[idx]; /* Each TFD can point to a maximum max_tbs Tx buffers */ - if (tfd->num_tbs >= trans_pcie->max_tbs) { + if (le16_to_cpu(tfd->num_tbs) >= trans_pcie->max_tbs) { IWL_ERR(trans, "Error can not send more than %d chunks\n", trans_pcie->max_tbs); return -EINVAL; @@ -334,7 +354,7 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, } /* Set up entry for this TFD in Tx byte-count array */ - iwl_pcie_gen2_update_byte_tbl(trans, txq, le16_to_cpu(tx_cmd->len), + iwl_pcie_gen2_update_byte_tbl(txq, le16_to_cpu(tx_cmd->len), iwl_pcie_gen2_get_num_tbs(trans, tfd)); /* start timer if queue currently empty */ @@ -781,26 +801,99 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) iwl_wake_queue(trans, txq); } +/* + * iwl_pcie_txq_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = trans_pcie->txq[txq_id]; + struct device *dev = trans->dev; + int i; + + if (WARN_ON(!txq)) + return; + + iwl_pcie_gen2_txq_unmap(trans, txq_id); + + /* De-alloc array of command/tx buffers */ + if (txq_id == trans_pcie->cmd_queue) + for (i = 0; i < txq->n_window; i++) { + kzfree(txq->entries[i].cmd); + kzfree(txq->entries[i].free_buf); + } + + /* De-alloc circular buffer of TFDs */ + if (txq->tfds) { + dma_free_coherent(dev, + trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX, + txq->tfds, txq->dma_addr); + dma_free_coherent(dev, + sizeof(*txq->first_tb_bufs) * txq->n_window, + txq->first_tb_bufs, txq->first_tb_dma); + } + + kfree(txq->entries); + + del_timer_sync(&txq->stuck_timer); + + iwl_pcie_free_dma_ptr(trans, &txq->bc_tbl); + kfree(txq); + trans_pcie->txq[txq_id] = NULL; + + clear_bit(txq_id, trans_pcie->queue_used); +} + int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, struct iwl_tx_queue_cfg_cmd *cmd, int cmd_id, unsigned int timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = trans_pcie->txq[cmd->scd_queue]; + struct iwl_txq *txq; struct iwl_host_cmd hcmd = { .id = cmd_id, .len = { sizeof(*cmd) }, .data = { cmd, }, .flags = 0, }; + int ret, qid = cmd->scd_queue; u16 ssn = le16_to_cpu(cmd->ssn); + txq = kzalloc(sizeof(*txq), GFP_KERNEL); + if (!txq) + return -ENOMEM; + ret = iwl_pcie_alloc_dma_ptr(trans, &txq->bc_tbl, + sizeof(struct iwlagn_scd_bc_tbl)); + if (ret) { + IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); + kfree(txq); + return -ENOMEM; + } + if (test_and_set_bit(cmd->scd_queue, trans_pcie->queue_used)) { WARN_ONCE(1, "queue %d already used", cmd->scd_queue); return -EINVAL; } + trans_pcie->txq[qid] = txq; + + ret = iwl_pcie_txq_alloc(trans, txq, TFD_TX_CMD_SLOTS, qid); + if (ret) { + IWL_ERR(trans, "Tx %d queue init failed\n", qid); + goto error; + } + ret = iwl_pcie_txq_init(trans, txq, TFD_TX_CMD_SLOTS, qid); + if (ret) { + IWL_ERR(trans, "Tx %d queue alloc failed\n", qid); + goto error; + } + txq->wd_timeout = msecs_to_jiffies(timeout); /* @@ -816,12 +909,14 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, cmd->scd_queue, ssn & 0xff); cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); - cmd->byte_cnt_addr = cpu_to_le64(trans_pcie->scd_bc_tbls.dma + - cmd->scd_queue * - sizeof(struct iwlagn_scd_bc_tbl)); - cmd->cb_size = cpu_to_le64(TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX)); + cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); + cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX)); return iwl_trans_send_cmd(trans, &hcmd); + +error: + iwl_pcie_gen2_txq_free(trans, cmd->scd_queue); + return -ENOMEM; } void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) @@ -845,3 +940,57 @@ void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", queue); } +void iwl_pcie_gen2_tx_free(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; + + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + + /* Free all TX queues */ + for (i = 0; i < ARRAY_SIZE(trans_pcie->txq); i++) { + if (!trans_pcie->txq[i]) + continue; + + iwl_pcie_gen2_txq_free(trans, i); + } +} + +int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *cmd_queue; + int txq_id = trans_pcie->cmd_queue, ret; + + /* alloc and init the command queue */ + if (!trans_pcie->txq[txq_id]) { + cmd_queue = kzalloc(sizeof(*cmd_queue), GFP_KERNEL); + if (!cmd_queue) { + IWL_ERR(trans, "Not enough memory for command queue\n"); + return -ENOMEM; + } + trans_pcie->txq[txq_id] = cmd_queue; + ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, + txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); + goto error; + } + } else { + cmd_queue = trans_pcie->txq[txq_id]; + } + + ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); + goto error; + } + set_bit(txq_id, trans_pcie->queue_used); + + return 0; + +error: + iwl_pcie_gen2_tx_free(trans); + return ret; +} + diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9ea92ac3920e4..df31e14bc33d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -126,8 +126,8 @@ static int iwl_queue_init(struct iwl_txq *q, int slots_num, u32 id) return 0; } -static int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, - struct iwl_dma_ptr *ptr, size_t size) +int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr, size_t size) { if (WARN_ON(ptr->addr)) return -EINVAL; @@ -140,8 +140,7 @@ static int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, return 0; } -static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, - struct iwl_dma_ptr *ptr) +void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr) { if (unlikely(!ptr->addr)) return; @@ -484,9 +483,8 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, return num_tbs; } -static int iwl_pcie_txq_alloc(struct iwl_trans *trans, - struct iwl_txq *txq, int slots_num, - u32 txq_id) +int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, + int slots_num, u32 txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); size_t tfd_sz = trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX; @@ -551,8 +549,8 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans, } -static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, - int slots_num, u32 txq_id) +int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, + int slots_num, u32 txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; @@ -778,6 +776,13 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int txq_id; + /* + * we should never get here in gen2 trans mode return early to avoid + * having invalid accesses + */ + if (WARN_ON_ONCE(trans->cfg->gen2)) + return; + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { struct iwl_txq *txq = trans_pcie->txq[txq_id]; @@ -1025,51 +1030,6 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) return ret; } -int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int ret; - int txq_id, slots_num; - bool alloc = false; - - if (!trans_pcie->txq_memory) { - /* TODO: change this when moving to new TX alloc model */ - ret = iwl_pcie_tx_alloc(trans); - if (ret) - goto error; - alloc = true; - } - - spin_lock(&trans_pcie->irq_lock); - - /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, - trans_pcie->kw.dma >> 4); - - spin_unlock(&trans_pcie->irq_lock); - - /* TODO: remove this when moving to new TX alloc model */ - for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; - txq_id++) { - slots_num = (txq_id == trans_pcie->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], - slots_num, txq_id); - if (ret) { - IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return 0; - -error: - /* Upon error, free only if we allocated something */ - if (alloc) - iwl_pcie_tx_free(trans); - return ret; -} - static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) { lockdep_assert_held(&txq->lock); From 6a90f85a696429ebe89777c6c895fd98fb36dc9b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 25 Jan 2017 18:57:26 +0200 Subject: [PATCH 130/201] iwlwifi: mvm: remove unnecessary label in iwl_mvm_handle_rx_statistics() The "invalid" label was a bit ugly and unnecessary. Remove it. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 655bd13841582..eab6e2ad62e1b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -660,8 +660,11 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, else expected_size = sizeof(struct iwl_notif_statistics_v10); - if (iwl_rx_packet_payload_len(pkt) != expected_size) - goto invalid; + if (iwl_rx_packet_payload_len(pkt) != expected_size) { + IWL_ERR(mvm, "received invalid statistics size (%d)!\n", + iwl_rx_packet_payload_len(pkt)); + return; + } data.mac_id = stats->rx.general.mac_id; data.beacon_filter_average_energy = @@ -714,12 +717,6 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, sta->avg_energy = energy[i]; } rcu_read_unlock(); - - return; - - invalid: - IWL_ERR(mvm, "received invalid statistics size (%d)!\n", - iwl_rx_packet_payload_len(pkt)); } void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) From b8e8d7cee32291a0cfdf813e45317b9d4d1b9574 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 17 Jan 2017 14:14:29 +0200 Subject: [PATCH 131/201] iwlwifi: pcie: get rid of txq id assignment In TVQM mode the queue ID is assigned after enablement. Get rid of assuming pre-defined TX queue ID in functions that will be used by TVQM allocation path. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/pcie/internal.h | 4 +- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 50 +++++++++++-------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 33 ++++++------ 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 405ae3799f5e1..b9e9e10c32fad 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -772,9 +772,9 @@ int iwl_queue_space(const struct iwl_txq *q); int iwl_pcie_apm_stop_master(struct iwl_trans *trans); void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, - int slots_num, u32 txq_id); + int slots_num, bool cmd_queue); int iwl_pcie_txq_alloc(struct iwl_trans *trans, - struct iwl_txq *txq, int slots_num, u32 txq_id); + struct iwl_txq *txq, int slots_num, bool cmd_queue); int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 446e837613a57..0bc9522cf3641 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -801,6 +801,27 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) iwl_wake_queue(trans, txq); } +static void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, + struct iwl_txq *txq) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct device *dev = trans->dev; + + /* De-alloc circular buffer of TFDs */ + if (txq->tfds) { + dma_free_coherent(dev, + trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX, + txq->tfds, txq->dma_addr); + dma_free_coherent(dev, + sizeof(*txq->first_tb_bufs) * txq->n_window, + txq->first_tb_bufs, txq->first_tb_dma); + } + + kfree(txq->entries); + iwl_pcie_free_dma_ptr(trans, &txq->bc_tbl); + kfree(txq); +} + /* * iwl_pcie_txq_free - Deallocate DMA queue. * @txq: Transmit queue to deallocate. @@ -813,7 +834,6 @@ static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = trans_pcie->txq[txq_id]; - struct device *dev = trans->dev; int i; if (WARN_ON(!txq)) @@ -827,23 +847,10 @@ static void iwl_pcie_gen2_txq_free(struct iwl_trans *trans, int txq_id) kzfree(txq->entries[i].cmd); kzfree(txq->entries[i].free_buf); } - - /* De-alloc circular buffer of TFDs */ - if (txq->tfds) { - dma_free_coherent(dev, - trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX, - txq->tfds, txq->dma_addr); - dma_free_coherent(dev, - sizeof(*txq->first_tb_bufs) * txq->n_window, - txq->first_tb_bufs, txq->first_tb_dma); - } - - kfree(txq->entries); - del_timer_sync(&txq->stuck_timer); - iwl_pcie_free_dma_ptr(trans, &txq->bc_tbl); - kfree(txq); + iwl_pcie_gen2_txq_free_memory(trans, txq); + trans_pcie->txq[txq_id] = NULL; clear_bit(txq_id, trans_pcie->queue_used); @@ -882,13 +889,14 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, } trans_pcie->txq[qid] = txq; + trans_pcie->txq[qid]->id = qid; - ret = iwl_pcie_txq_alloc(trans, txq, TFD_TX_CMD_SLOTS, qid); + ret = iwl_pcie_txq_alloc(trans, txq, TFD_TX_CMD_SLOTS, false); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", qid); goto error; } - ret = iwl_pcie_txq_init(trans, txq, TFD_TX_CMD_SLOTS, qid); + ret = iwl_pcie_txq_init(trans, txq, TFD_TX_CMD_SLOTS, false); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", qid); goto error; @@ -970,8 +978,7 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) return -ENOMEM; } trans_pcie->txq[txq_id] = cmd_queue; - ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, - txq_id); + ret = iwl_pcie_txq_alloc(trans, cmd_queue, TFD_CMD_SLOTS, true); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; @@ -980,11 +987,12 @@ int iwl_pcie_gen2_tx_init(struct iwl_trans *trans) cmd_queue = trans_pcie->txq[txq_id]; } - ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, txq_id); + ret = iwl_pcie_txq_init(trans, cmd_queue, TFD_CMD_SLOTS, true); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); goto error; } + trans_pcie->txq[txq_id]->id = txq_id; set_bit(txq_id, trans_pcie->queue_used); return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index df31e14bc33d3..386950a2d6162 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -102,10 +102,9 @@ int iwl_queue_space(const struct iwl_txq *q) /* * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -static int iwl_queue_init(struct iwl_txq *q, int slots_num, u32 id) +static int iwl_queue_init(struct iwl_txq *q, int slots_num) { q->n_window = slots_num; - q->id = id; /* slots_num must be power-of-two size, otherwise * get_cmd_index is broken. */ @@ -484,7 +483,7 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, } int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, - int slots_num, u32 txq_id) + int slots_num, bool cmd_queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); size_t tfd_sz = trans_pcie->tfd_size * TFD_QUEUE_SIZE_MAX; @@ -507,7 +506,7 @@ int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, if (!txq->entries) goto error; - if (txq_id == trans_pcie->cmd_queue) + if (cmd_queue) for (i = 0; i < slots_num; i++) { txq->entries[i].cmd = kmalloc(sizeof(struct iwl_device_cmd), @@ -533,13 +532,11 @@ int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, if (!txq->first_tb_bufs) goto err_free_tfds; - txq->id = txq_id; - return 0; err_free_tfds: dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->dma_addr); error: - if (txq->entries && txq_id == trans_pcie->cmd_queue) + if (txq->entries && cmd_queue) for (i = 0; i < slots_num; i++) kfree(txq->entries[i].cmd); kfree(txq->entries); @@ -550,9 +547,8 @@ int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, } int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, - int slots_num, u32 txq_id) + int slots_num, bool cmd_queue) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; txq->need_update = false; @@ -562,13 +558,13 @@ int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue's high/low-water marks, and head/tail indexes */ - ret = iwl_queue_init(txq, slots_num, txq_id); + ret = iwl_queue_init(txq, slots_num); if (ret) return ret; spin_lock_init(&txq->lock); - if (txq_id == trans_pcie->cmd_queue) { + if (cmd_queue) { static struct lock_class_key iwl_pcie_cmd_queue_lock_class; lockdep_set_class(&txq->lock, &iwl_pcie_cmd_queue_lock_class); @@ -951,15 +947,17 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { - slots_num = (txq_id == trans_pcie->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + bool cmd_queue = (txq_id == trans_pcie->cmd_queue); + + slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; trans_pcie->txq[txq_id] = &trans_pcie->txq_memory[txq_id]; ret = iwl_pcie_txq_alloc(trans, trans_pcie->txq[txq_id], - slots_num, txq_id); + slots_num, cmd_queue); if (ret) { IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); goto error; } + trans_pcie->txq[txq_id]->id = txq_id; } return 0; @@ -998,10 +996,11 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { - slots_num = (txq_id == trans_pcie->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + bool cmd_queue = (txq_id == trans_pcie->cmd_queue); + + slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], - slots_num, txq_id); + slots_num, cmd_queue); if (ret) { IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); goto error; From 12db294c7872eeb0e3ff595cd985e369325dde0e Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 17 Jan 2017 14:28:21 +0200 Subject: [PATCH 132/201] iwlwifi: mvm: support new TX response for TVQM In TVQM mode the TX responses were changed to include queue number since legacy TX queue number retrieval cannot be scaled up to 512 queues. Support this change. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/fw-api-tx.h | 42 ++++++++----------- .../net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 10 +++++ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 34 +++++++++++++-- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index f83ee6e760d07..e9f055706a6fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -548,9 +548,11 @@ struct agg_tx_status { * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control + * @tx_queue: TX queue for this response * @status: for non-agg: frame status TX_STATUS_* * for agg: status of 1st frame, AGG_TX_STATE_*; other frame status fields * follow this one, up to frame_count. + * For version 6 TX response isn't received for aggregation at all. * * After the array of statuses comes the SSN of the SCD. Look at * %iwl_mvm_get_scd_ssn for more details. @@ -577,9 +579,17 @@ struct iwl_mvm_tx_resp { u8 tlc_info; u8 ra_tid; __le16 frame_ctrl; - - struct agg_tx_status status; -} __packed; /* TX_RSP_API_S_VER_3 */ + union { + struct { + struct agg_tx_status status; + } v3;/* TX_RSP_API_S_VER_3 */ + struct { + __le16 tx_queue; + __le16 reserved2; + struct agg_tx_status status; + } v6; + }; +} __packed; /* TX_RSP_API_S_VER_6 */ /** * struct iwl_mvm_ba_notif - notifies about reception of BA @@ -619,11 +629,14 @@ struct iwl_mvm_ba_notif { * struct iwl_mvm_compressed_ba_tfd - progress of a TFD queue * @q_num: TFD queue number * @tfd_index: Index of first un-acked frame in the TFD queue + * @scd_queue: For debug only - the physical queue the TFD queue is bound to */ struct iwl_mvm_compressed_ba_tfd { - u8 q_num; - u8 reserved; + __le16 q_num; __le16 tfd_index; + u8 scd_queue; + u8 reserved; + __le16 reserved2; } __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */ /** @@ -799,25 +812,6 @@ struct iwl_tx_path_flush_cmd { __le16 reserved; } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_1 */ -/** - * iwl_mvm_get_scd_ssn - returns the SSN of the SCD - * @tx_resp: the Tx response from the fw (agg or non-agg) - * - * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since - * it can't know that everything will go well until the end of the AMPDU, it - * can't know in advance the number of MPDUs that will be sent in the current - * batch. This is why it writes the agg Tx response while it fetches the MPDUs. - * Hence, it can't know in advance what the SSN of the SCD will be at the end - * of the batch. This is why the SSN of the SCD is written at the end of the - * whole struct at a variable offset. This function knows how to cope with the - * variable offset and returns the SSN of the SCD. - */ -static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp) -{ - return le32_to_cpup((__le32 *)&tx_resp->status + - tx_resp->frame_count) & 0xfff; -} - /* Available options for the SCD_QUEUE_CFG HCMD */ enum iwl_scd_cfg_actions { SCD_CFG_DISABLE_QUEUE = 0x0, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index ae1406fe99889..9e69b9d2012cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1443,6 +1443,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_mvm_tx_resp *beacon_notify_hdr; struct ieee80211_vif *csa_vif; struct ieee80211_vif *tx_blocked_vif; + struct agg_tx_status *agg_status; u16 status; lockdep_assert_held(&mvm->mutex); @@ -1450,7 +1451,8 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, beacon_notify_hdr = &beacon->beacon_notify_hdr; mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); - status = le16_to_cpu(beacon_notify_hdr->status.status) & TX_STATUS_MSK; + agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); + status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", status, beacon_notify_hdr->failure_frame, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 2205c9f8bb587..70abc6cd3b474 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1250,6 +1250,16 @@ static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CDB_SUPPORT); } +static inline struct agg_tx_status* +iwl_mvm_get_agg_status(struct iwl_mvm *mvm, + struct iwl_mvm_tx_resp *tx_resp) +{ + if (iwl_mvm_has_new_tx_api(mvm)) + return &tx_resp->v6.status; + else + return &tx_resp->v3.status; +} + static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm) { #ifdef CONFIG_THERMAL diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 4ba7ff44420da..90c33ee69f212 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1282,6 +1282,26 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, } } +/** + * iwl_mvm_get_scd_ssn - returns the SSN of the SCD + * @tx_resp: the Tx response from the fw (agg or non-agg) + * + * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since + * it can't know that everything will go well until the end of the AMPDU, it + * can't know in advance the number of MPDUs that will be sent in the current + * batch. This is why it writes the agg Tx response while it fetches the MPDUs. + * Hence, it can't know in advance what the SSN of the SCD will be at the end + * of the batch. This is why the SSN of the SCD is written at the end of the + * whole struct at a variable offset. This function knows how to cope with the + * variable offset and returns the SSN of the SCD. + */ +static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm, + struct iwl_mvm_tx_resp *tx_resp) +{ + return le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) + + tx_resp->frame_count) & 0xfff; +} + static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { @@ -1291,8 +1311,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid); int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); - u32 status = le16_to_cpu(tx_resp->status.status); - u16 ssn = iwl_mvm_get_scd_ssn(tx_resp); + struct agg_tx_status *agg_status = + iwl_mvm_get_agg_status(mvm, tx_resp); + u32 status = le16_to_cpu(agg_status->status); + u16 ssn = iwl_mvm_get_scd_ssn(mvm, tx_resp); struct iwl_mvm_sta *mvmsta; struct sk_buff_head skbs; u8 skb_freed = 0; @@ -1301,6 +1323,9 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, __skb_queue_head_init(&skbs); + if (iwl_mvm_has_new_tx_api(mvm)) + txq_id = le16_to_cpu(tx_resp->v6.tx_queue); + seq_ctl = le16_to_cpu(tx_resp->seq_ctl); /* we can free until ssn % q.n_bd not inclusive */ @@ -1557,7 +1582,8 @@ static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; - struct agg_tx_status *frame_status = &tx_resp->status; + struct agg_tx_status *frame_status = + iwl_mvm_get_agg_status(mvm, tx_resp); int i; for (i = 0; i < tx_resp->frame_count; i++) { @@ -1772,7 +1798,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) if (tid == IWL_MGMT_TID) tid = IWL_MAX_TID_COUNT; iwl_mvm_tx_reclaim(mvm, sta_id, tid, - (int)ba_res->tfd[0].q_num, + (int)(le16_to_cpu(ba_res->tfd[0].q_num)), le16_to_cpu(ba_res->tfd[0].tfd_index), &ba_info, le32_to_cpu(ba_res->tx_rate)); From 310181ec34e20134dc1b1c8b5e62605af83b1777 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 17 Jan 2017 14:27:48 +0200 Subject: [PATCH 133/201] iwlwifi: move to TVQM mode In TVQM firmware returns the value of the queue ID and code should accept it. The TX queue config API was changed. Move to new API. This has to be done in parallel in mvm and pcie. Do not move yet to 512 queues since there are some opens with enabling it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-trans.h | 38 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 + drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 124 +++++++++++++----- .../net/wireless/intel/iwlwifi/mvm/utils.c | 63 ++++++--- .../net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 70 ++++++---- 5 files changed, 202 insertions(+), 96 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index c87a58ee012a5..626e2703a57f1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -531,37 +531,43 @@ struct iwl_trans_txq_scd_cfg { int frame_limit; }; +/* Available options for &struct iwl_tx_queue_cfg_cmd */ +enum iwl_tx_queue_cfg_actions { + TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), + TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), +}; + /** * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command - * @token: token of the command * @sta_id: station id * @tid: tid of the queue - * @scd_queue: scheduler queue to config - * @action: 1 queue enable, 0 queue disable - * @aggregate: 1 aggregated queue, 0 otherwise - * @tx_fifo: TX fifo - * @window: BA window size - * @ssn: SSN for the BA agreement + * @flags: Bit 0 - on enable, off - disable, Bit 1 - short TFD format * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) * @byte_cnt_addr: address of byte count table * @tfdq_addr: address of TFD circular buffer */ struct iwl_tx_queue_cfg_cmd { - u8 token; u8 sta_id; u8 tid; - u8 scd_queue; - u8 action; - u8 aggregate; - u8 tx_fifo; - u8 window; - __le16 ssn; - __le16 reserved; + __le16 flags; __le32 cb_size; __le64 byte_cnt_addr; __le64 tfdq_addr; -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_1 */ +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config + * @queue_number: queue number assigned to this RA -TID + * @flags: set on failure + * @write_pointer: initial value for write pointer + */ +struct iwl_tx_queue_cfg_rsp { + __le16 queue_number; + __le16 flags; + __le16 write_pointer; + __le16 reserved; +} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ /** * struct iwl_trans_ops - transport specific operations diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 70abc6cd3b474..a22fe45eecc48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1699,6 +1699,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout); +int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, + u8 sta_id, u8 tid, unsigned int timeout); + /* * Disable a TXQ. * Note that in non-DQA mode the %mac80211_queue and %tid params are ignored. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 36ae228c16125..ea35fcbd3b266 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -702,6 +702,41 @@ int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, return ret; } +static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, u8 ac, + int tid) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); + u8 mac_queue = mvmsta->vif->hw_queue[ac]; + int queue = -1; + + lockdep_assert_held(&mvm->mutex); + + IWL_DEBUG_TX_QUEUES(mvm, + "Allocating queue for sta %d on tid %d\n", + mvmsta->sta_id, tid); + queue = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, mvmsta->sta_id, tid, + wdg_timeout); + if (queue < 0) + return queue; + + IWL_DEBUG_TX_QUEUES(mvm, "Allocated queue is %d\n", queue); + + spin_lock_bh(&mvmsta->lock); + mvmsta->tid_data[tid].txq_id = queue; + mvmsta->tid_data[tid].is_tid_active = true; + mvmsta->tfd_queue_msk |= BIT(queue); + spin_unlock_bh(&mvmsta->lock); + + spin_lock_bh(&mvm->queue_info_lock); + mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; + spin_unlock_bh(&mvm->queue_info_lock); + + return 0; +} + static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u8 ac, int tid, struct ieee80211_hdr *hdr) @@ -727,6 +762,9 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + if (iwl_mvm_has_new_tx_api(mvm)) + return iwl_mvm_sta_alloc_queue_tvqm(mvm, sta, ac, tid); + spin_lock_bh(&mvmsta->lock); tfd_queue_mask = mvmsta->tfd_queue_msk; spin_unlock_bh(&mvmsta->lock); @@ -782,15 +820,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, /* No free queue - we'll have to share */ if (queue <= 0) { - /* This shouldn't happen in new HW - we have 512 queues */ - if (WARN(iwl_mvm_has_new_tx_api(mvm), - "No available queues for tid %d on sta_id %d\n", - tid, cfg.sta_id)) { - spin_unlock_bh(&mvm->queue_info_lock); - - return queue; - } - queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac); if (queue > 0) { shared_queue = true; @@ -875,9 +904,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE; spin_unlock_bh(&mvmsta->lock); - if (iwl_mvm_has_new_tx_api(mvm)) - return 0; - if (!shared_queue) { ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES); if (ret) @@ -1243,18 +1269,30 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, ac = tid_to_mac80211_ac[i]; mac_queue = mvm_sta->vif->hw_queue[ac]; - cfg.tid = i; - cfg.fifo = iwl_mvm_ac_to_tx_fifo[ac]; - cfg.aggregate = (txq_id >= IWL_MVM_DQA_MIN_DATA_QUEUE || - txq_id == IWL_MVM_DQA_BSS_CLIENT_QUEUE); + if (iwl_mvm_has_new_tx_api(mvm)) { + IWL_DEBUG_TX_QUEUES(mvm, + "Re-mapping sta %d tid %d\n", + mvm_sta->sta_id, i); + txq_id = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, + mvm_sta->sta_id, + i, wdg_timeout); + tid_data->txq_id = txq_id; + } else { + u16 seq = IEEE80211_SEQ_TO_SN(tid_data->seq_number); - IWL_DEBUG_TX_QUEUES(mvm, - "Re-mapping sta %d tid %d to queue %d\n", - mvm_sta->sta_id, i, txq_id); + cfg.tid = i; + cfg.fifo = iwl_mvm_ac_to_tx_fifo[ac]; + cfg.aggregate = (txq_id >= IWL_MVM_DQA_MIN_DATA_QUEUE || + txq_id == + IWL_MVM_DQA_BSS_CLIENT_QUEUE); - iwl_mvm_enable_txq(mvm, txq_id, mac_queue, - IEEE80211_SEQ_TO_SN(tid_data->seq_number), - &cfg, wdg_timeout); + IWL_DEBUG_TX_QUEUES(mvm, + "Re-mapping sta %d tid %d to queue %d\n", + mvm_sta->sta_id, i, txq_id); + + iwl_mvm_enable_txq(mvm, txq_id, mac_queue, seq, &cfg, + wdg_timeout); + } mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; } @@ -1751,7 +1789,13 @@ static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) mvm->cfg->base_params->wd_timeout : IWL_WATCHDOG_DISABLED; - if (iwl_mvm_is_dqa_supported(mvm)) { + if (iwl_mvm_has_new_tx_api(mvm)) { + int queue = iwl_mvm_tvqm_enable_txq(mvm, mvm->aux_queue, + mvm->aux_sta.sta_id, + IWL_MAX_TID_COUNT, + wdg_timeout); + mvm->aux_queue = queue; + } else if (iwl_mvm_is_dqa_supported(mvm)) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = IWL_MVM_TX_FIFO_MCAST, .sta_id = mvm->aux_sta.sta_id, @@ -1863,7 +1907,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (iwl_mvm_is_dqa_supported(mvm)) { + if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) queue = mvm->probe_queue; @@ -1874,9 +1918,8 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) bsta->tfd_queue_msk |= BIT(queue); - if (!iwl_mvm_has_new_tx_api(mvm)) - iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, - &cfg, wdg_timeout); + iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, + &cfg, wdg_timeout); } if (vif->type == NL80211_IFTYPE_ADHOC) @@ -1894,9 +1937,18 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * For a000 firmware and on we cannot add queue to a station unknown * to firmware so enable queue here - after the station was added */ - if (iwl_mvm_has_new_tx_api(mvm)) - iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, &cfg, - wdg_timeout); + if (iwl_mvm_has_new_tx_api(mvm)) { + int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->hw_queue[0], + bsta->sta_id, + IWL_MAX_TID_COUNT, + wdg_timeout); + if (vif->type == NL80211_IFTYPE_AP) + mvm->probe_queue = queue; + else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + mvm->p2p_dev_queue = queue; + + bsta->tfd_queue_msk |= BIT(queue); + } return 0; } @@ -2064,8 +2116,16 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * This is needed for a000 firmware which won't accept SCD_QUEUE_CFG * command with unknown station id. */ - iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, &cfg, - timeout); + if (iwl_mvm_has_new_tx_api(mvm)) { + int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue, + msta->sta_id, + IWL_MAX_TID_COUNT, + timeout); + vif->cab_queue = queue; + } else { + iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, + &cfg, timeout); + } return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 70ec048ac1525..1dde05697c29e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -695,14 +695,47 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, return enable_queue; } +int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, + u8 sta_id, u8 tid, unsigned int timeout) +{ + struct iwl_tx_queue_cfg_cmd cmd = { + .flags = cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), + .sta_id = sta_id, + .tid = tid, + }; + int queue; + + if (cmd.tid == IWL_MAX_TID_COUNT) + cmd.tid = IWL_MGMT_TID; + queue = iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, + SCD_QUEUE_CFG, timeout); + + if (queue < 0) { + IWL_DEBUG_TX_QUEUES(mvm, + "Failed allocating TXQ for sta %d tid %d, ret: %d\n", + sta_id, tid, queue); + return queue; + } + + IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", + queue, sta_id, tid); + + iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, sta_id, tid); + + return queue; +} + void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + /* Send the enabling command if we need to */ if (iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, cfg->sta_id, cfg->tid)) { - struct iwl_tx_queue_cfg_cmd cmd = { + struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_ENABLE_QUEUE, .window = cfg->frame_limit, @@ -713,14 +746,6 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, .tid = cfg->tid, }; - if (iwl_mvm_has_new_tx_api(mvm)) { - if (cmd.tid == IWL_MAX_TID_COUNT) - cmd.tid = IWL_MGMT_TID; - iwl_trans_txq_alloc(mvm->trans, (void *)&cmd, - SCD_QUEUE_CFG, wdg_timeout); - return; - } - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, @@ -734,12 +759,11 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u8 tid, u8 flags) { - struct iwl_tx_queue_cfg_cmd cmd = { + struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; bool remove_mac_queue = true; - int ret; spin_lock_bh(&mvm->queue_info_lock); @@ -812,22 +836,21 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, if (iwl_mvm_has_new_tx_api(mvm)) { iwl_trans_txq_free(mvm->trans, queue); - if (cmd.tid == IWL_MAX_TID_COUNT) - cmd.tid = IWL_MGMT_TID; - ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, - sizeof(cmd), &cmd); } else { + int ret; + iwl_trans_txq_disable(mvm->trans, queue, false); ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, sizeof(struct iwl_scd_txq_cfg_cmd), &cmd); - } - if (ret) - IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", - queue, ret); + if (ret) + IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", + queue, ret); + return ret; + } - return ret; + return 0; } /** diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 0bc9522cf3641..9fb46a6f47cf4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -862,15 +862,15 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, unsigned int timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue_cfg_rsp *rsp; struct iwl_txq *txq; struct iwl_host_cmd hcmd = { .id = cmd_id, .len = { sizeof(*cmd) }, .data = { cmd, }, - .flags = 0, + .flags = CMD_WANT_SKB, }; - int ret, qid = cmd->scd_queue; - u16 ssn = le16_to_cpu(cmd->ssn); + int ret, qid; txq = kzalloc(sizeof(*txq), GFP_KERNEL); if (!txq) @@ -883,48 +883,62 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, return -ENOMEM; } - if (test_and_set_bit(cmd->scd_queue, trans_pcie->queue_used)) { - WARN_ONCE(1, "queue %d already used", cmd->scd_queue); - return -EINVAL; - } - - trans_pcie->txq[qid] = txq; - trans_pcie->txq[qid]->id = qid; - ret = iwl_pcie_txq_alloc(trans, txq, TFD_TX_CMD_SLOTS, false); if (ret) { - IWL_ERR(trans, "Tx %d queue init failed\n", qid); + IWL_ERR(trans, "Tx queue alloc failed\n"); goto error; } ret = iwl_pcie_txq_init(trans, txq, TFD_TX_CMD_SLOTS, false); if (ret) { - IWL_ERR(trans, "Tx %d queue alloc failed\n", qid); + IWL_ERR(trans, "Tx queue init failed\n"); goto error; } txq->wd_timeout = msecs_to_jiffies(timeout); - /* - * Place first TFD at index corresponding to start sequence number. - * Assumes that ssn_idx is valid (!= 0xFFF) - */ - txq->read_ptr = (ssn & 0xff); - txq->write_ptr = (ssn & 0xff); - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (cmd->scd_queue << 16)); - - IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d WrPtr: %d\n", - cmd->scd_queue, ssn & 0xff); - cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX)); - return iwl_trans_send_cmd(trans, &hcmd); + ret = iwl_trans_send_cmd(trans, &hcmd); + if (ret) + goto error; + + if (WARN_ON(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp))) { + ret = -EINVAL; + goto error; + } + + rsp = (void *)hcmd.resp_pkt->data; + qid = le16_to_cpu(rsp->queue_number); + + if (qid > ARRAY_SIZE(trans_pcie->txq)) { + WARN_ONCE(1, "queue index %d unsupported", qid); + ret = -EIO; + goto error; + } + + if (test_and_set_bit(qid, trans_pcie->queue_used)) { + WARN_ONCE(1, "queue %d already used", qid); + ret = -EIO; + goto error; + } + + txq->id = qid; + trans_pcie->txq[qid] = txq; + + /* Place first TFD at index corresponding to start sequence number */ + txq->read_ptr = le16_to_cpu(rsp->write_pointer); + txq->write_ptr = le16_to_cpu(rsp->write_pointer); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, + (txq->write_ptr) | (qid << 16)); + IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid); + + return qid; error: - iwl_pcie_gen2_txq_free(trans, cmd->scd_queue); - return -ENOMEM; + iwl_pcie_gen2_txq_free_memory(trans, txq); + return ret; } void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) From 5a4aa895521bb0f7148e34de69059799f9cb1690 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 1 Feb 2017 16:21:32 +0200 Subject: [PATCH 134/201] iwlwifi: mvm: remove unneeded reg write in iwl_mvm_up() Not only that this write is not needed (as FW does this itself), on newer HW this register is write protected so trying to write there will cause problems. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 3 --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index e1aa1f7836fc1..4bceaccee62f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -294,9 +294,6 @@ /*********************** END TX SCHEDULER *************************************/ -/* tcp checksum offload */ -#define RX_EN_CSUM (0x00a00d88) - /* Oscillator clock */ #define OSC_CLK (0xa04068) #define OSC_CLK_FORCE_CONTROL (0x8) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 2a4c952ef01a5..bfccbadd1a6ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1475,10 +1475,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - if (iwl_mvm_is_csum_supported(mvm) && - mvm->cfg->features & NETIF_F_RXCSUM) - iwl_trans_write_prph(mvm->trans, RX_EN_CSUM, 0x3); - /* allow FW/transport low power modes if not during restart */ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); From bbf049d92a718ddba70d72388dcdea5304a3f723 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 19 May 2016 16:19:22 +0300 Subject: [PATCH 135/201] iwlwifi: mvm: do not turn on RX_FLAG_AMSDU_MORE This flag is used for mac80211 reordering. As we do reordering ourselves, turning it on is misleading and pointless. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 29c9c56ed3fa3..44072c3c4b5fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -917,9 +917,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, u8 *qc = ieee80211_get_qos_ctl(hdr); *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; - if (!(desc->amsdu_info & - IWL_RX_MPDU_AMSDU_LAST_SUBFRAME)) - rx_status->flag |= RX_FLAG_AMSDU_MORE; } if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) iwl_mvm_agg_rx_received(mvm, baid); From a56cb4f0d826359d98adf12cb5e0a2de35e8aa59 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 31 Jan 2017 14:36:10 +0200 Subject: [PATCH 136/201] iwlwifi: mvm: work around HW issue with AMSDU de-aggregation Seems like HW is reversing addr3 in the MAC header of de-aggregated AMSDU. Reverse it back. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 44072c3c4b5fa..c99775039f592 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -911,12 +911,19 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, * Our hardware de-aggregates AMSDUs but copies the mac header * as it to the de-aggregated MPDUs. We need to turn off the * AMSDU bit in the QoS control ourselves. + * In addition, HW reverses addr3 - reverse it back. */ if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { + int i; u8 *qc = ieee80211_get_qos_ctl(hdr); + u8 mac_addr[ETH_ALEN]; *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1]; + ether_addr_copy(hdr->addr3, mac_addr); } if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) iwl_mvm_agg_rx_received(mvm, baid); From 0f17e1bb8447f1cd2228c363a86c36340b87fa08 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 4 Jan 2017 09:30:24 +0200 Subject: [PATCH 137/201] iwlwifi: mvm: change TX_CMD_SEC_KEY_FROM_TABLE value Change the value of TX_CMD_SEC_KEY_FROM_TABLE flag in TX_CMD security flags to accommodate a FW API change. Bump min API for 9000 series devices to 30 to keep the driver aligned aligned the FW. Signed-off-by: David Spinadel Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-9000.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c index d265b279b2caf..110ceefccc153 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-9000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-9000.c @@ -58,7 +58,7 @@ #define IWL9000_UCODE_API_MAX 30 /* Lowest firmware API version supported */ -#define IWL9000_UCODE_API_MIN 17 +#define IWL9000_UCODE_API_MIN 30 /* NVM versions */ #define IWL9000_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index e9f055706a6fd..81b98915b1a42 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -174,7 +174,7 @@ enum iwl_tx_cmd_sec_ctrl { TX_CMD_SEC_EXT = 0x04, TX_CMD_SEC_GCMP = 0x05, TX_CMD_SEC_KEY128 = 0x08, - TX_CMD_SEC_KEY_FROM_TABLE = 0x08, + TX_CMD_SEC_KEY_FROM_TABLE = 0x10, }; /* TODO: how does these values are OK with only 16 bit variable??? */ From 5d43eab6632df3a5b5bfc79025860dc4583ed0f4 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 2 Feb 2017 12:51:39 +0200 Subject: [PATCH 138/201] iwlwifi: mvm: ignore BAID for SN smaller than SSN When we get SN that is smaller than SSN of the aggregation, we shouldn't apply any reordering on them. Further more, HW NSSN will be zeroed, which can cause us to make some invalid decisions. Detect the situation and invalidate the BAID. Fixes: b915c10174fb ("iwlwifi: mvm: add reorder buffer per queue") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 30 +++++++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 1 + 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a22fe45eecc48..32e62175cbd50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -626,6 +626,7 @@ struct iwl_mvm_shared_mem_cfg { * @reorder_timer: timer for frames are in the reorder buffer. For AMSDU * it is the time of last received sub-frame * @removed: prevent timer re-arming + * @valid: reordering is valid for this queue * @lock: protect reorder buffer internal state * @mvm: mvm pointer, needed for frame timer context */ @@ -641,6 +642,7 @@ struct iwl_mvm_reorder_buffer { unsigned long reorder_time[IEEE80211_MAX_AMPDU_BUF]; struct timer_list reorder_timer; bool removed; + bool valid; spinlock_t lock; struct iwl_mvm *mvm; } ____cacheline_aligned_in_smp; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index c99775039f592..8601d25407b3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -636,9 +636,13 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, return false; baid_data = rcu_dereference(mvm->baid_map[baid]); - if (WARN(!baid_data, - "Received baid %d, but no data exists for this BAID\n", baid)) + if (!baid_data) { + WARN(!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN), + "Received baid %d, but no data exists for this BAID\n", + baid); return false; + } + if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id, "baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n", baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id, @@ -653,6 +657,14 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, spin_lock_bh(&buffer->lock); + if (!buffer->valid) { + if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) { + spin_unlock_bh(&buffer->lock); + return false; + } + buffer->valid = true; + } + if (ieee80211_is_back_req(hdr->frame_control)) { iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn); goto drop; @@ -737,7 +749,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, return true; } -static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid) +static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, + u32 reorder_data, u8 baid) { unsigned long now = jiffies; unsigned long timeout; @@ -746,8 +759,10 @@ static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid) rcu_read_lock(); data = rcu_dereference(mvm->baid_map[baid]); - if (WARN_ON(!data)) + if (!data) { + WARN_ON(!(reorder_data & IWL_RX_MPDU_REORDER_BA_OLD_SN)); goto out; + } if (!data->timeout) goto out; @@ -925,8 +940,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1]; ether_addr_copy(hdr->addr3, mac_addr); } - if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) - iwl_mvm_agg_rx_received(mvm, baid); + if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) { + u32 reorder_data = le32_to_cpu(desc->reorder_data); + + iwl_mvm_agg_rx_received(mvm, reorder_data, baid); + } } /* Set up the HT phy flags */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ea35fcbd3b266..cc9c92b8e2ba2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2231,6 +2231,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm, reorder_buf->mvm = mvm; reorder_buf->queue = i; reorder_buf->sta_id = sta_id; + reorder_buf->valid = false; for (j = 0; j < reorder_buf->buf_size; j++) __skb_queue_head_init(&reorder_buf->entries[j]); } From e71ca5ea7466a7a38bb6cd83388623e47f62467b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 8 Feb 2017 14:53:32 +0200 Subject: [PATCH 139/201] iwlwifi: mvm: provide the actual number of frames for the SP len In the end, the firmware doesn't want the SP len as present in the WMM IE, but rather the actual number of frames. Fixes: bd3c6cf901a8 ("iwlwifi: mvm: tell the firmware about the U-APSD parameters") Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index cc9c92b8e2ba2..a2a1fa06b7814 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -223,7 +223,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) add_sta_cmd.uapsd_acs |= BIT(AC_VO); add_sta_cmd.uapsd_acs |= add_sta_cmd.uapsd_acs << 4; - add_sta_cmd.sp_length = sta->max_sp; + add_sta_cmd.sp_length = sta->max_sp ? sta->max_sp * 2 : 128; } status = ADD_STA_SUCCESS; From f27588938a585d38f2ed9e7398b24d0a2b421abf Mon Sep 17 00:00:00 2001 From: Tzipi Peres Date: Sun, 12 Feb 2017 11:08:08 +0200 Subject: [PATCH 140/201] iwlwifi: add four new 8265 and 8275 series PCI IDs Add one new PCI ID for the 8265 series. Add three new PCI ID for the 8275 series. Signed-off-by: Tzipi Peres Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d38fcc1a47683..52e1d0c9428d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -501,6 +501,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x0930, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0950, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0850, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x1014, iwl8265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x3E02, iwl8275_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x3E01, iwl8275_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24FD, 0x1012, iwl8275_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0012, iwl8275_2ac_cfg)}, /* 9000 Series */ From fa1f2b617a94ff734fe2d5136bbda4e4f2d22635 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Thu, 26 Jan 2017 12:40:25 +0200 Subject: [PATCH 141/201] iwlwifi: mvm: support change to a000 smem API API was changed once more to support 2 LMACs. Adapt to change while preserving current functionality. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 2 + .../net/wireless/intel/iwlwifi/mvm/fw-api.h | 41 ++- .../net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 287 ++++++++++-------- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 53 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 11 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- 6 files changed, 241 insertions(+), 155 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 4bceaccee62f3..f832e58e0ef99 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -314,6 +314,8 @@ #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) +#define LMAC2_PRPH_OFFSET (0x100000) + /* Rx FIFO */ #define RXF_SIZE_ADDR (0xa00c88) #define RXF_RD_D_SPACE (0xa00c40) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index dd2bd7c3587c3..56f50d8a7b69b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -2026,19 +2026,48 @@ struct iwl_shared_mem_cfg_v1 { __le32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_2 */ +/** + * struct iwl_shared_mem_lmac_cfg - LMAC shared memory configuration + * + * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB) + * @txfifo_size: size of TX FIFOs + * @rxfifo1_addr: RXF1 addr + * @rxfifo1_size: RXF1 size + */ +struct iwl_shared_mem_lmac_cfg { + __le32 txfifo_addr; + __le32 txfifo_size[TX_FIFO_MAX_NUM]; + __le32 rxfifo1_addr; + __le32 rxfifo1_size; + +} __packed; /* SHARED_MEM_ALLOC_LMAC_API_S_VER_1 */ + +/** + * Shared memory configuration information from the FW + * + * @shared_mem_addr: shared memory address + * @shared_mem_size: shared memory size + * @sample_buff_addr: internal sample (mon/adc) buff addr + * @sample_buff_size: internal sample buff size + * @rxfifo2_addr: start addr of RXF2 + * @rxfifo2_size: size of RXF2 + * @page_buff_addr: used by UMAC and performance debug (page miss analysis), + * when paging is not supported this should be 0 + * @page_buff_size: size of %page_buff_addr + * @lmac_num: number of LMACs (1 or 2) + * @lmac_smem: per - LMAC smem data + */ struct iwl_shared_mem_cfg { __le32 shared_mem_addr; __le32 shared_mem_size; __le32 sample_buff_addr; __le32 sample_buff_size; - __le32 txfifo_addr; - __le32 txfifo_size[TX_FIFO_MAX_NUM]; - __le32 rxfifo_size[RX_FIFO_MAX_NUM]; + __le32 rxfifo2_addr; + __le32 rxfifo2_size; __le32 page_buff_addr; __le32 page_buff_size; - __le32 rxfifo_addr; - __le32 internal_txfifo_addr; - __le32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; + __le32 lmac_num; + struct iwl_shared_mem_lmac_cfg lmac_smem[2]; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index a027b11bbdb38..7b86a4f1b574c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -7,7 +7,7 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -99,10 +99,120 @@ static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm, iwl_trans_release_nic_access(mvm->trans, &flags); } +static void iwl_mvm_dump_rxf(struct iwl_mvm *mvm, + struct iwl_fw_error_dump_data **dump_data, + int size, u32 offset, int fifo_num) +{ + struct iwl_fw_error_dump_fifo *fifo_hdr; + u32 *fifo_data; + u32 fifo_len; + int i; + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = size; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + return; + + /* Add a TLV for the RXF */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(fifo_num); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_D_SPACE + offset)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_WR_PTR + offset)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_RD_PTR + offset)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_FENCE_PTR + offset)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_SET_FENCE_MODE + offset)); + + /* Lock fence */ + iwl_trans_write_prph(mvm->trans, RXF_SET_FENCE_MODE + offset, 0x1); + /* Set fence pointer to the same place like WR pointer */ + iwl_trans_write_prph(mvm->trans, RXF_LD_WR2FENCE + offset, 0x1); + /* Set fence offset */ + iwl_trans_write_prph(mvm->trans, + RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (i = 0; i < fifo_len; i++) + fifo_data[i] = iwl_trans_read_prph(mvm->trans, + RXF_FIFO_RD_FENCE_INC + + offset); + *dump_data = iwl_fw_error_next_data(*dump_data); +} + +static void iwl_mvm_dump_txf(struct iwl_mvm *mvm, + struct iwl_fw_error_dump_data **dump_data, + int size, u32 offset, int fifo_num) +{ + struct iwl_fw_error_dump_fifo *fifo_hdr; + u32 *fifo_data; + u32 fifo_len; + int i; + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = size; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + return; + + /* Add a TLV for the FIFO */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(fifo_num); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FIFO_ITEM_CNT + offset)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_WR_PTR + offset)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_RD_PTR + offset)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FENCE_PTR + offset)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_LOCK_FENCE + offset)); + + /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ + iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR + offset, + TXF_WR_PTR + offset); + + /* Dummy-read to advance the read pointer to the head */ + iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA + offset); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (i = 0; i < fifo_len; i++) + fifo_data[i] = iwl_trans_read_prph(mvm->trans, + TXF_READ_MODIFY_DATA + + offset); + *dump_data = iwl_fw_error_next_data(*dump_data); +} + static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, struct iwl_fw_error_dump_data **dump_data) { struct iwl_fw_error_dump_fifo *fifo_hdr; + struct iwl_mvm_shared_mem_cfg *cfg = &mvm->smem_cfg; u32 *fifo_data; u32 fifo_len; unsigned long flags; @@ -111,126 +221,47 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) return; - /* Pull RXF data from all RXFs */ - for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) { - /* - * Keep aside the additional offset that might be needed for - * next RXF - */ - u32 offset_diff = RXF_DIFF_FROM_PREV * i; - - fifo_hdr = (void *)(*dump_data)->data; - fifo_data = (void *)fifo_hdr->data; - fifo_len = mvm->shared_mem_cfg.rxfifo_size[i]; - - /* No need to try to read the data if the length is 0 */ - if (fifo_len == 0) - continue; - - /* Add a TLV for the RXF */ - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); - (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); - - fifo_hdr->fifo_num = cpu_to_le32(i); - fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - RXF_RD_D_SPACE + - offset_diff)); - fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - RXF_RD_WR_PTR + - offset_diff)); - fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - RXF_RD_RD_PTR + - offset_diff)); - fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - RXF_RD_FENCE_PTR + - offset_diff)); - fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - RXF_SET_FENCE_MODE + - offset_diff)); - - /* Lock fence */ - iwl_trans_write_prph(mvm->trans, - RXF_SET_FENCE_MODE + offset_diff, 0x1); - /* Set fence pointer to the same place like WR pointer */ - iwl_trans_write_prph(mvm->trans, - RXF_LD_WR2FENCE + offset_diff, 0x1); - /* Set fence offset */ - iwl_trans_write_prph(mvm->trans, - RXF_LD_FENCE_OFFSET_ADDR + offset_diff, - 0x0); - - /* Read FIFO */ - fifo_len /= sizeof(u32); /* Size in DWORDS */ - for (j = 0; j < fifo_len; j++) - fifo_data[j] = iwl_trans_read_prph(mvm->trans, - RXF_FIFO_RD_FENCE_INC + - offset_diff); - *dump_data = iwl_fw_error_next_data(*dump_data); - } - - /* Pull TXF data from all TXFs */ - for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) { + /* Pull RXF1 */ + iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); + /* Pull RXF2 */ + iwl_mvm_dump_rxf(mvm, dump_data, cfg->rxfifo2_size, + RXF_DIFF_FROM_PREV, 1); + /* Pull LMAC2 RXF1 */ + if (mvm->smem_cfg.num_lmacs > 1) + iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[1].rxfifo1_size, + LMAC2_PRPH_OFFSET, 2); + + /* Pull TXF data from LMAC1 */ + for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); + iwl_mvm_dump_txf(mvm, dump_data, cfg->lmac[0].txfifo_size[i], + 0, i); + } - fifo_hdr = (void *)(*dump_data)->data; - fifo_data = (void *)fifo_hdr->data; - fifo_len = mvm->shared_mem_cfg.txfifo_size[i]; - - /* No need to try to read the data if the length is 0 */ - if (fifo_len == 0) - continue; - - /* Add a TLV for the FIFO */ - (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); - (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); - - fifo_hdr->fifo_num = cpu_to_le32(i); - fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - TXF_FIFO_ITEM_CNT)); - fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - TXF_WR_PTR)); - fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - TXF_RD_PTR)); - fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - TXF_FENCE_PTR)); - fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, - TXF_LOCK_FENCE)); - - /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ - iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR, - TXF_WR_PTR); - - /* Dummy-read to advance the read pointer to the head */ - iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA); - - /* Read FIFO */ - fifo_len /= sizeof(u32); /* Size in DWORDS */ - for (j = 0; j < fifo_len; j++) - fifo_data[j] = iwl_trans_read_prph(mvm->trans, - TXF_READ_MODIFY_DATA); - *dump_data = iwl_fw_error_next_data(*dump_data); + /* Pull TXF data from LMAC2 */ + if (mvm->smem_cfg.num_lmacs > 1) { + for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { + /* Mark the number of TXF we're pulling now */ + iwl_trans_write_prph(mvm->trans, + TXF_LARC_NUM + LMAC2_PRPH_OFFSET, + i); + iwl_mvm_dump_txf(mvm, dump_data, + cfg->lmac[1].txfifo_size[i], + LMAC2_PRPH_OFFSET, + i + cfg->num_txfifo_entries); + } } if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ for (i = 0; - i < ARRAY_SIZE(mvm->shared_mem_cfg.internal_txfifo_size); + i < ARRAY_SIZE(mvm->smem_cfg.internal_txfifo_size); i++) { fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; - fifo_len = mvm->shared_mem_cfg.internal_txfifo_size[i]; + fifo_len = mvm->smem_cfg.internal_txfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) @@ -246,7 +277,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i + - ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size)); + mvm->smem_cfg.num_txfifo_entries); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, @@ -553,31 +584,45 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) /* reading RXF/TXF sizes */ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { - struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg; + struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->smem_cfg; fifo_data_len = 0; - /* Count RXF size */ - for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) { - if (!mem_cfg->rxfifo_size[i]) - continue; - + /* Count RXF2 size */ + if (mem_cfg->rxfifo2_size) { /* Add header info */ - fifo_data_len += mem_cfg->rxfifo_size[i] + + fifo_data_len += mem_cfg->rxfifo2_size + sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } - for (i = 0; i < mem_cfg->num_txfifo_entries; i++) { - if (!mem_cfg->txfifo_size[i]) + /* Count RXF1 sizes */ + for (i = 0; i < mem_cfg->num_lmacs; i++) { + if (!mem_cfg->lmac[i].rxfifo1_size) continue; /* Add header info */ - fifo_data_len += mem_cfg->txfifo_size[i] + + fifo_data_len += mem_cfg->lmac[i].rxfifo1_size + sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } + /* Count TXF sizes */ + for (i = 0; i < mem_cfg->num_lmacs; i++) { + int j; + + for (j = 0; j < mem_cfg->num_txfifo_entries; j++) { + if (!mem_cfg->lmac[i].txfifo_size[j]) + continue; + + /* Add header info */ + fifo_data_len += + mem_cfg->lmac[i].txfifo_size[j] + + sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + } + } + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { for (i = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index bfccbadd1a6ec..a845233d14a3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -897,24 +897,27 @@ static void iwl_mvm_parse_shared_mem_a000(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) { struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data; - int i; + int i, lmac; + int lmac_num = le32_to_cpu(mem_cfg->lmac_num); - mvm->shared_mem_cfg.num_txfifo_entries = - ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); - for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) - mvm->shared_mem_cfg.txfifo_size[i] = - le32_to_cpu(mem_cfg->txfifo_size[i]); - for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) - mvm->shared_mem_cfg.rxfifo_size[i] = - le32_to_cpu(mem_cfg->rxfifo_size[i]); + if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) + return; - BUILD_BUG_ON(sizeof(mvm->shared_mem_cfg.internal_txfifo_size) != - sizeof(mem_cfg->internal_txfifo_size)); + mvm->smem_cfg.num_lmacs = lmac_num; + mvm->smem_cfg.num_txfifo_entries = + ARRAY_SIZE(mem_cfg->lmac_smem[0].txfifo_size); + mvm->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); - for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.internal_txfifo_size); - i++) - mvm->shared_mem_cfg.internal_txfifo_size[i] = - le32_to_cpu(mem_cfg->internal_txfifo_size[i]); + for (lmac = 0; lmac < lmac_num; lmac++) { + struct iwl_shared_mem_lmac_cfg *lmac_cfg = + &mem_cfg->lmac_smem[lmac]; + + for (i = 0; i < ARRAY_SIZE(lmac_cfg->txfifo_size); i++) + mvm->smem_cfg.lmac[lmac].txfifo_size[i] = + le32_to_cpu(lmac_cfg->txfifo_size[i]); + mvm->smem_cfg.lmac[lmac].rxfifo1_size = + le32_to_cpu(lmac_cfg->rxfifo1_size); + } } static void iwl_mvm_parse_shared_mem(struct iwl_mvm *mvm, @@ -923,25 +926,27 @@ static void iwl_mvm_parse_shared_mem(struct iwl_mvm *mvm, struct iwl_shared_mem_cfg_v1 *mem_cfg = (void *)pkt->data; int i; - mvm->shared_mem_cfg.num_txfifo_entries = - ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); + mvm->smem_cfg.num_lmacs = 1; + + mvm->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size); for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) - mvm->shared_mem_cfg.txfifo_size[i] = + mvm->smem_cfg.lmac[0].txfifo_size[i] = le32_to_cpu(mem_cfg->txfifo_size[i]); - for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) - mvm->shared_mem_cfg.rxfifo_size[i] = - le32_to_cpu(mem_cfg->rxfifo_size[i]); + + mvm->smem_cfg.lmac[0].rxfifo1_size = + le32_to_cpu(mem_cfg->rxfifo_size[0]); + mvm->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo_size[1]); /* new API has more data, from rxfifo_addr field and on */ if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { - BUILD_BUG_ON(sizeof(mvm->shared_mem_cfg.internal_txfifo_size) != + BUILD_BUG_ON(sizeof(mvm->smem_cfg.internal_txfifo_size) != sizeof(mem_cfg->internal_txfifo_size)); for (i = 0; - i < ARRAY_SIZE(mvm->shared_mem_cfg.internal_txfifo_size); + i < ARRAY_SIZE(mvm->smem_cfg.internal_txfifo_size); i++) - mvm->shared_mem_cfg.internal_txfifo_size[i] = + mvm->smem_cfg.internal_txfifo_size[i] = le32_to_cpu(mem_cfg->internal_txfifo_size[i]); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 32e62175cbd50..14b8c2eba7fcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -604,10 +604,15 @@ enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_ACTIVE, }; +#define MAX_NUM_LMAC 2 struct iwl_mvm_shared_mem_cfg { + int num_lmacs; int num_txfifo_entries; - u32 txfifo_size[TX_FIFO_MAX_NUM]; - u32 rxfifo_size[RX_FIFO_MAX_NUM]; + struct { + u32 txfifo_size[TX_FIFO_MAX_NUM]; + u32 rxfifo1_size; + } lmac[MAX_NUM_LMAC]; + u32 rxfifo2_size; u32 internal_txfifo_addr; u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; }; @@ -1034,7 +1039,7 @@ struct iwl_mvm { } peer; } tdls_cs; - struct iwl_mvm_shared_mem_cfg shared_mem_cfg; + struct iwl_mvm_shared_mem_cfg smem_cfg; u32 ciphers[IWL_MVM_NUM_CIPHERS]; struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 90c33ee69f212..ed7ee50046459 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -744,7 +744,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * fifo to be able to send bursts. */ max_amsdu_len = min_t(unsigned int, max_amsdu_len, - mvm->shared_mem_cfg.txfifo_size[txf] - 256); + mvm->smem_cfg.lmac[0].txfifo_size[txf] - 256); if (unlikely(dbg_max_amsdu_len)) max_amsdu_len = min_t(unsigned int, max_amsdu_len, From 386f49361a356f3f5c6afe076b9a61b54ac16a3f Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 22 Jan 2017 17:17:19 +0200 Subject: [PATCH 142/201] iwlwifi: support a000 CDB product Identify and load FW for a000 CDB product. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 20 +++++++++++++++---- .../net/wireless/intel/iwlwifi/iwl-config.h | 5 ++++- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 7 ++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index df4e8714d627c..1c731b88d08c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2015-2016 Intel Deutschland GmbH + * Copyright(c) 2015-2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,7 +18,7 @@ * * BSD LICENSE * - * Copyright(c) 2015-2016 Intel Deutschland GmbH + * Copyright(c) 2015-2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,8 +72,9 @@ #define IWL_A000_SMEM_OFFSET 0x400000 #define IWL_A000_SMEM_LEN 0x68000 -#define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" -#define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" +#define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" +#define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" +#define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-a0-hrcdb-a0-" #define IWL_A000_HR_MODULE_FIRMWARE(api) \ IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" @@ -134,6 +135,17 @@ const struct iwl_cfg iwla000_2ac_cfg_hr = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwla000_2ac_cfg_hr_cdb = { + .name = "Intel(R) Dual Band Wireless AC a000", + .fw_name_pre = IWL_A000_HR_CDB_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .cdb = true, +}; + const struct iwl_cfg iwla000_2ac_cfg_jf = { .name = "Intel(R) Dual Band Wireless AC a000", .fw_name_pre = IWL_A000_JF_FW_PRE, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 06034a71a1905..4af1267181a96 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -314,6 +314,7 @@ struct iwl_pwr_tx_backoff { * @rf_id: need to read rf_id to determine the firmware image * @integrated: discrete or integrated * @gen2: a000 and on transport operation + * @cdb: CDB support * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -360,7 +361,8 @@ struct iwl_cfg { rf_id:1, integrated:1, use_tfh:1, - gen2:1; + gen2:1, + cdb:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; @@ -450,6 +452,7 @@ extern const struct iwl_cfg iwl9270_2ac_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg; extern const struct iwl_cfg iwla000_2ac_cfg_hr; +extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 52e1d0c9428d4..e51760e752d48 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -537,7 +537,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg)}, /* a000 Series */ - {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, + {IWL_PCI_DEVICE(0x2722, 0x0A10, iwla000_2ac_cfg_hr)}, #endif /* CONFIG_IWLMVM */ {0} @@ -672,8 +673,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } if (iwl_trans->cfg->rf_id && - (cfg == &iwla000_2ac_cfg_hr && - iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF)) { + (cfg == &iwla000_2ac_cfg_hr || cfg == &iwla000_2ac_cfg_hr_cdb) && + iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) { cfg = &iwla000_2ac_cfg_jf; iwl_trans->cfg = cfg; } From 528709b081dbf2bc86de072280a11634918c1e53 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Mon, 13 Feb 2017 09:48:17 +0200 Subject: [PATCH 143/201] iwlwifi: pcie: remove RSA race workaround This workaround is not needed anymore. Remove it. Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/pcie/trans.c | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index ed1034e58cb42..91f6030529b32 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -720,47 +720,6 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, return ret; } -/* - * Driver Takes the ownership on secure machine before FW load - * and prevent race with the BT load. - * W/A for ROM bug. (should be remove in the next Si step) - */ -static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) -{ - u32 val, loop = 1000; - - /* - * Check the RSA semaphore is accessible. - * If the HW isn't locked and the rsa semaphore isn't accessible, - * we are in trouble. - */ - val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0); - if (val & (BIT(1) | BIT(17))) { - IWL_DEBUG_INFO(trans, - "can't access the RSA semaphore it is write protected\n"); - return 0; - } - - /* take ownership on the AUX IF */ - iwl_write_prph(trans, WFPM_CTRL_REG, WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK); - iwl_write_prph(trans, AUX_MISC_MASTER1_EN, AUX_MISC_MASTER1_EN_SBE_MSK); - - do { - iwl_write_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS, 0x1); - val = iwl_read_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS); - if (val == 0x1) { - iwl_write_prph(trans, RSA_ENABLE, 0); - return 0; - } - - udelay(10); - loop--; - } while (loop > 0); - - IWL_ERR(trans, "Failed to take ownership on secure machine\n"); - return -EIO; -} - static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, const struct fw_img *image, int cpu, @@ -1010,11 +969,6 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, if (trans->dbg_dest_tlv) iwl_pcie_apply_destination(trans); - /* TODO: remove in the next Si step */ - ret = iwl_pcie_rsa_race_bug_wa(trans); - if (ret) - return ret; - IWL_DEBUG_POWER(trans, "Original WFPM value = 0x%08X\n", iwl_read_prph(trans, WFPM_GP2)); From a6bff3cb19b7d57e297a11d844ffb71be9fd9d80 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 19 Jan 2017 12:00:46 +0200 Subject: [PATCH 144/201] iwlwifi: mvm: add GEO_TX_POWER_LIMIT cmd for geographic tx power table To utilize the maximum allowed tx power, an additional table was added to the BIOS. The table consists of up to seven different regions (currently only three are in use). Each region contains per band: 1. Maximum allowed tx power on the band. 2. Tx power offset for chain A. 3. Tx power offset for chain B. On init flow driver reads this table by means of ACPI and passes it to the firmware with GEO_TX_POWER_LIMIT cmd. The firmware will use this table to enhance tx power with the offset in the relevant table as well as verifying it does not violate the maximum allowed tx power. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/mvm/fw-api-power.h | 43 ++++++- .../net/wireless/intel/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 112 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 5 files changed, 160 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h index 3fa43d1348a22..750510aff70b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -351,6 +351,45 @@ struct iwl_dev_tx_power_cmd { u8 reserved[3]; } __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ +#define IWL_NUM_GEO_PROFILES 3 + +/** + * enum iwl_geo_per_chain_offset_operation - type of operation + * @IWL_PER_CHAIN_OFFSET_SET_TABLES: send the tables from the host to the FW. + * @IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE: retrieve the last configured table. + */ +enum iwl_geo_per_chain_offset_operation { + IWL_PER_CHAIN_OFFSET_SET_TABLES, + IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE, +}; /* GEO_TX_POWER_LIMIT FLAGS TYPE */ + +/** + * struct iwl_per_chain_offset - embedded struct for GEO_TX_POWER_LIMIT. + * @max_tx_power: maximum allowed tx power. + * @chain_a: tx power offset for chain a. + * @chain_b: tx power offset for chain b. + */ +struct iwl_per_chain_offset { + __le16 max_tx_power; + u8 chain_a; + u8 chain_b; +} __packed; /* PER_CHAIN_LIMIT_OFFSET_PER_CHAIN_S_VER_1 */ + +struct iwl_per_chain_offset_group { + struct iwl_per_chain_offset lb; + struct iwl_per_chain_offset hb; +} __packed; /* PER_CHAIN_LIMIT_OFFSET_GROUP_S_VER_1 */ + +/** + * struct iwl_geo_tx_power_profile_cmd - struct for GEO_TX_POWER_LIMIT cmd. + * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation + * @table: offset profile per band. + */ +struct iwl_geo_tx_power_profiles_cmd { + __le32 ops; + struct iwl_per_chain_offset_group table[IWL_NUM_GEO_PROFILES]; +} __packed; /* GEO_TX_POWER_LIMIT */ + /** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 56f50d8a7b69b..5086dc00346c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -320,6 +320,7 @@ enum iwl_phy_ops_subcmd_ids { CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, CTDP_CONFIG_CMD = 0x03, TEMP_REPORTING_THRESHOLDS_CMD = 0x04, + GEO_TX_POWER_LIMIT = 0x05, CT_KILL_NOTIFICATION = 0xFE, DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a845233d14a3c..bce3cf5fab675 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -998,10 +998,14 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) #ifdef CONFIG_ACPI #define ACPI_WRDS_METHOD "WRDS" #define ACPI_EWRD_METHOD "EWRD" +#define ACPI_WGDS_METHOD "WGDS" #define ACPI_WIFI_DOMAIN (0x07) #define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2) #define ACPI_EWRD_WIFI_DATA_SIZE ((IWL_MVM_SAR_PROFILE_NUM - 1) * \ IWL_MVM_SAR_TABLE_SIZE + 3) +#define ACPI_WGDS_WIFI_DATA_SIZE 18 +#define ACPI_WGDS_NUM_BANDS 2 +#define ACPI_WGDS_TABLE_SIZE 3 static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, union acpi_object *table, @@ -1203,6 +1207,61 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) return ret; } +static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm, + struct iwl_mvm_geo_table *geo_table) +{ + union acpi_object *wifi_pkg; + acpi_handle root_handle; + acpi_handle handle; + struct acpi_buffer wgds = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + int i, ret; + + root_handle = ACPI_HANDLE(mvm->dev); + if (!root_handle) { + IWL_DEBUG_RADIO(mvm, + "Could not retrieve root port ACPI handle\n"); + return -ENOENT; + } + + /* Get the method's handle */ + status = acpi_get_handle(root_handle, (acpi_string)ACPI_WGDS_METHOD, + &handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "WGDS method not found\n"); + return -ENOENT; + } + + /* Call WGDS with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &wgds); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "WGDS invocation failed (0x%x)\n", status); + return -ENOENT; + } + + wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, wgds.pointer, + ACPI_WGDS_WIFI_DATA_SIZE); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + for (i = 0; i < ACPI_WGDS_WIFI_DATA_SIZE; i++) { + union acpi_object *entry; + + entry = &wifi_pkg->package.elements[i + 1]; + if ((entry->type != ACPI_TYPE_INTEGER) || + (entry->integer.value > U8_MAX)) + return -EINVAL; + + geo_table->values[i] = entry->integer.value; + } + ret = 0; +out_free: + kfree(wgds.pointer); + return ret; +} + int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { struct iwl_dev_tx_power_cmd cmd = { @@ -1256,6 +1315,50 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) +{ + struct iwl_mvm_geo_table geo_table; + struct iwl_geo_tx_power_profiles_cmd cmd = { + .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), + }; + int ret, i, j, idx; + u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); + + ret = iwl_mvm_sar_get_wgds_table(mvm, &geo_table); + if (ret < 0) { + IWL_DEBUG_RADIO(mvm, + "Geo SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + return 0; + } + + IWL_DEBUG_RADIO(mvm, "Sending GEO_TX_POWER_LIMIT\n"); + + BUILD_BUG_ON(IWL_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS * + ACPI_WGDS_TABLE_SIZE != ACPI_WGDS_WIFI_DATA_SIZE); + + for (i = 0; i < IWL_NUM_GEO_PROFILES; i++) { + struct iwl_per_chain_offset *chain = + (struct iwl_per_chain_offset *)&cmd.table[i]; + + for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { + u8 *value; + + idx = i * ACPI_WGDS_NUM_BANDS * ACPI_WGDS_TABLE_SIZE + + j * ACPI_WGDS_TABLE_SIZE; + value = &geo_table.values[idx]; + chain[j].max_tx_power = cpu_to_le16(value[0]); + chain[j].chain_a = value[1]; + chain[j].chain_b = value[2]; + IWL_DEBUG_RADIO(mvm, + "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", + i, j, value[1], value[2], value[0]); + } + } + return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd); +} + #else /* CONFIG_ACPI */ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) { @@ -1266,6 +1369,11 @@ static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) { return -ENOENT; } + +static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) +{ + return 0; +} #endif /* CONFIG_ACPI */ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) @@ -1488,6 +1596,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + ret = iwl_mvm_sar_geo_init(mvm); + if (ret) + goto error; + IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 14b8c2eba7fcb..1938dfb441525 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -720,11 +720,16 @@ enum iwl_mvm_queue_status { #ifdef CONFIG_ACPI #define IWL_MVM_SAR_TABLE_SIZE 10 #define IWL_MVM_SAR_PROFILE_NUM 4 +#define IWL_MVM_GEO_TABLE_SIZE 18 struct iwl_mvm_sar_profile { bool enabled; u8 table[IWL_MVM_SAR_TABLE_SIZE]; }; + +struct iwl_mvm_geo_table { + u8 values[IWL_MVM_GEO_TABLE_SIZE]; +}; #endif struct iwl_mvm { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d313941ffc9d4..488d3c948fe84 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -446,6 +446,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), HCMD_NAME(CTDP_CONFIG_CMD), HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD), + HCMD_NAME(GEO_TX_POWER_LIMIT), HCMD_NAME(CT_KILL_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE), }; From 4399caaa70bb30f538fc0c3b08a7a8f128ca5f12 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 11 Dec 2016 10:32:42 +0200 Subject: [PATCH 145/201] iwlwifi: mvm: support init extended command When we load firmware in extended mode (as we do by default for now) driver should send a command what kind of commands ucode should stop and wait for before proceeding with phy calibrations. Support this command. Currently we only do NVM access - so mark this bit only. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api.h | 23 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 15 ++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 1 + 3 files changed, 39 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 5086dc00346c0..8302cf03ac288 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -327,6 +327,7 @@ enum iwl_phy_ops_subcmd_ids { enum iwl_system_subcmd_ids { SHARED_MEM_CFG_CMD = 0x0, + INIT_EXTENDED_CFG_CMD = 0x03, }; enum iwl_data_path_subcmd_ids { @@ -2236,4 +2237,26 @@ struct iwl_nvm_access_complete_cmd { __le32 reserved; } __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ +/** + * enum iwl_extended_cfg_flag - commands driver may send before + * finishing init flow + * @IWL_INIT_DEBUG_CFG: driver is going to send debug config command + * @IWL_INIT_NVM: driver is going to send NVM_ACCESS commands + * @IWL_INIT_PHY: driver is going to send PHY_DB commands + */ +enum iwl_extended_cfg_flags { + IWL_INIT_DEBUG_CFG, + IWL_INIT_NVM, + IWL_INIT_PHY, +}; + +/** + * struct iwl_extended_cfg_cmd - mark what commands ucode should wait for + * before finishing init flows + * @init_flags: values from iwl_extended_cfg_flags + */ +struct iwl_init_extended_cfg_cmd { + __le32 init_flags; +} __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index bce3cf5fab675..900f1e25b9dac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -836,6 +836,9 @@ int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) { struct iwl_notification_wait init_wait; struct iwl_nvm_access_complete_cmd nvm_complete = {}; + struct iwl_init_extended_cfg_cmd init_cfg = { + .init_flags = cpu_to_le32(BIT(IWL_INIT_NVM)), + }; static const u16 init_complete[] = { INIT_COMPLETE_NOTIF, }; @@ -857,6 +860,18 @@ int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) goto error; } + /* Send init config command to mark that we are sending NVM access + * commands + */ + ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, + INIT_EXTENDED_CFG_CMD), 0, + sizeof(init_cfg), &init_cfg); + if (ret) { + IWL_ERR(mvm, "Failed to run init config command: %d\n", + ret); + goto error; + } + /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { /* Read nvm */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 488d3c948fe84..888053323c925 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -428,6 +428,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { HCMD_NAME(SHARED_MEM_CFG_CMD), + HCMD_NAME(INIT_EXTENDED_CFG_CMD), }; /* Please keep this array *SORTED* by hex value. From bc0294696456365f1e80fa8a0a6e13d076316b30 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Feb 2017 13:17:11 +0200 Subject: [PATCH 146/201] iwlwifi: mvm: disable RX queue notification for a000 devices For a000 devices, we don't really have multi RX queue for now, until we have the RX queue configuration API. Disable RX queue notification for now. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 26cf3dfcc108e..f35f295d0c819 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4218,7 +4218,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (!iwl_mvm_has_new_rx_api(mvm)) + /* TODO - remove a000 disablement when we have RXQ config API */ + if (!iwl_mvm_has_new_rx_api(mvm) || iwl_mvm_has_new_tx_api(mvm)) return; notif->cookie = mvm->queue_sync_cookie; From cb2de6bb4f129683673da907b71344d59a38c55a Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Feb 2017 13:36:31 +0200 Subject: [PATCH 147/201] iwlwifi: mvm: dump frames early on invalid rate Currently when rate isn't found (invalid rate or CCK rate in high band) driver is assigning rate -1, which causes mac80211 to dump it later with the cryptic rate value of 0xFF. Instead, warn early and dump the frame in mvm. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 13 ++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 18 +++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index eab6e2ad62e1b..d4c0ca7ccb342 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -460,9 +460,16 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, if (rate_n_flags & RATE_MCS_BF_MSK) rx_status->vht_flag |= RX_VHT_FLAG_BF; } else { - rx_status->rate_idx = - iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, - rx_status->band); + int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, + rx_status->band); + + if (WARN(rate < 0 || rate > 0xFF, + "Invalid rate flags 0x%x, band %d,\n", + rate_n_flags, rx_status->band)) { + kfree_skb(skb); + return; + } + rx_status->rate_idx = rate; } #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 8601d25407b3d..0f74a200e8125 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -918,8 +918,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { kfree_skb(skb); - rcu_read_unlock(); - return; + goto out; } /* @@ -985,9 +984,17 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (rate_n_flags & RATE_MCS_BF_MSK) rx_status->vht_flag |= RX_VHT_FLAG_BF; } else { - rx_status->rate_idx = - iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, - rx_status->band); + int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, + rx_status->band); + + if (WARN(rate < 0 || rate > 0xFF, + "Invalid rate flags 0x%x, band %d,\n", + rate_n_flags, rx_status->band)) { + kfree_skb(skb); + goto out; + } + rx_status->rate_idx = rate; + } /* management stuff on default queue */ @@ -1006,6 +1013,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb); if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta); +out: rcu_read_unlock(); } From 2220fb2960b72915e7fd9da640a4695dceff238c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 13 Feb 2017 11:29:16 +0200 Subject: [PATCH 148/201] iwlwifi: split the handler and the wake parts of the notification infra The notification infrastructure (iwl_notification_wait_* functions) allows to wait until a list of notifications will come up from the firmware and to run a special handler (notif_wait handler) when those are received. The operation mode notifies the notification infrastructure about any Rx being received by the mean of iwl_notification_wait_notify() which will do two things: 1) call the notif_wait handler 2) wakeup the thread that was waiting for the notification Typically, only after those two steps happened, the operation mode will run its own handler for the notification that was received from the firmware. This means that the thread that was waiting for that notification can be running before the operation mode's handler was called. When the operation mode's handler is ASYNC, things get even worse since the thread that was waiting for the notification isn't even guaranteed that the ASYNC callback was added to async_handlers_list before it starts to run. This means that even calling iwl_mvm_wait_for_async_handlers() can't guarantee that absolutely everything related to that notification has run. The following can happen: Thread sending the command Operation mode's Rx path -------------------------- ------------------------ iwl_init_notification_wait() iwl_mvm_send_cmd() iwl_mvm_rx_common() iwl_notification_wait_notify() iwl_mvm_wait_for_async_handlers() // Possibly free some data // structure list_add_tail(async_handlers_list); schedule_work(async_handlers_wk); // Access the freed structure Split the 'run notif_wait's handler' and the 'wake up the thread' parts to fix this. This allows the operation mode to do the following: Thread sending the command Operation mode's Rx path -------------------------- ------------------------ iwl_init_notification_wait() iwl_mvm_send_cmd() iwl_mvm_rx_common() iwl_notification_wait() // Will run the notif_wait's handler list_add_tail(async_handlers_list); schedule_work(async_handlers_wk); iwl_notification_notify() iwl_mvm_wait_for_async_handlers() This way, the waiter is guaranteed that all the handlers have been run (if SYNC), or at least enqueued (if ASYNC) by the time it wakes up. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- .../wireless/intel/iwlwifi/iwl-notif-wait.c | 10 +++----- .../wireless/intel/iwlwifi/iwl-notif-wait.h | 25 +++++++++++++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c index 88f260db37440..68412ff2112e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c @@ -76,8 +76,8 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) } IWL_EXPORT_SYMBOL(iwl_notification_wait_init); -void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt) +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt) { bool triggered = false; @@ -118,13 +118,11 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, } } spin_unlock(¬if_wait->notif_wait_lock); - } - if (triggered) - wake_up_all(¬if_wait->notif_waitq); + return triggered; } -IWL_EXPORT_SYMBOL(iwl_notification_wait_notify); +IWL_EXPORT_SYMBOL(iwl_notification_wait); void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h index 0f9995ed71cde..368884be4e7c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,10 +90,10 @@ struct iwl_notif_wait_data { * * This structure is not used directly, to wait for a * notification declare it on the stack, and call - * iwlagn_init_notification_wait() with appropriate + * iwl_init_notification_wait() with appropriate * parameters. Then do whatever will cause the ucode * to notify the driver, and to wait for that then - * call iwlagn_wait_notification(). + * call iwl_wait_notification(). * * Each notification is one-shot. If at some point we * need to support multi-shot notifications (which @@ -114,10 +115,24 @@ struct iwl_notification_wait { /* caller functions */ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data); -void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt); +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt); void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); +static inline void +iwl_notification_notify(struct iwl_notif_wait_data *notif_data) +{ + wake_up_all(¬if_data->notif_waitq); +} + +static inline void +iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt) +{ + if (iwl_notification_wait(notif_data, pkt)) + iwl_notification_notify(notif_data); +} + /* user functions */ void __acquires(wait_entry) iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, From 9dfa21517a75d6c06d9e9a92814101eaebba168b Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 14 Feb 2017 14:58:21 +0200 Subject: [PATCH 149/201] iwlwifi: mvm: flip address 4 of AMSDU frames Address 4 is reversed as well. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 0f74a200e8125..24c4fbe139a36 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -925,7 +925,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, * Our hardware de-aggregates AMSDUs but copies the mac header * as it to the de-aggregated MPDUs. We need to turn off the * AMSDU bit in the QoS control ourselves. - * In addition, HW reverses addr3 - reverse it back. + * In addition, HW reverses addr3 and addr4 - reverse it back. */ if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { @@ -938,6 +938,13 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, for (i = 0; i < ETH_ALEN; i++) mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1]; ether_addr_copy(hdr->addr3, mac_addr); + + if (ieee80211_has_a4(hdr->frame_control)) { + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = + hdr->addr4[ETH_ALEN - i - 1]; + ether_addr_copy(hdr->addr4, mac_addr); + } } if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) { u32 reorder_data = le32_to_cpu(desc->reorder_data); From 730a18912bcbde0b94ae7f1b554a9908b3424a22 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 7 Feb 2017 18:37:40 +0200 Subject: [PATCH 150/201] iwlwifi: mvm: support changing band for phy context In a000 CDB firmware, we cannot update phy context to a different band - we must first remove it and add it again. Support this flow for all a000 devices since we may have various combinations that cause us to fail regardless if CDB is active. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api.h | 2 +- .../net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 8302cf03ac288..f545c5f9e4e38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -690,7 +690,7 @@ struct iwl_error_resp { (_color << FW_CTXT_COLOR_POS)) /* Possible actions on PHYs, MACs and Bindings */ -enum { +enum iwl_phy_ctxt_action { FW_CTXT_ACTION_STUB = 0, FW_CTXT_ACTION_ADD, FW_CTXT_ACTION_MODIFY, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 95138830b9f8e..d59efe8043561 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -250,12 +251,30 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { + enum iwl_phy_ctxt_action action = FW_CTXT_ACTION_MODIFY; + lockdep_assert_held(&mvm->mutex); + /* In CDB mode we cannot modify PHY context between bands so... */ + if (iwl_mvm_has_new_tx_api(mvm) && + ctxt->channel->band != chandef->chan->band) { + int ret; + + /* ... remove it here ...*/ + ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, + chains_static, chains_dynamic, + FW_CTXT_ACTION_REMOVE, 0); + if (ret) + return ret; + + /* ... and proceed to add it again */ + action = FW_CTXT_ACTION_ADD; + } + ctxt->channel = chandef->chan; return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, chains_static, chains_dynamic, - FW_CTXT_ACTION_MODIFY, 0); + action, 0); } void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) From f4d1047914ea05e0f8393944da18f6ee5dad24c4 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 19 Feb 2017 10:42:40 +0200 Subject: [PATCH 151/201] iwlwifi: a000: fix memory offsets and lengths Memory offsets and lengths for A000 HW is different than currently specified. Fixes: e34d975e40ff ("iwlwifi: Add a000 HW family support") Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index 1c731b88d08c6..097cb45c8ad92 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -65,12 +65,12 @@ #define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */ /* Memory offsets and lengths */ -#define IWL_A000_DCCM_OFFSET 0x800000 -#define IWL_A000_DCCM_LEN 0x18000 +#define IWL_A000_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_A000_DCCM_LEN 0x10000 /* LMAC1 */ #define IWL_A000_DCCM2_OFFSET 0x880000 #define IWL_A000_DCCM2_LEN 0x8000 #define IWL_A000_SMEM_OFFSET 0x400000 -#define IWL_A000_SMEM_LEN 0x68000 +#define IWL_A000_SMEM_LEN 0xD0000 #define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" #define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" From 9b1ea16763d37080892e4425831ca9c6298f4f5c Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 19 Feb 2017 17:00:58 +0200 Subject: [PATCH 152/201] iwlwifi: mvm: allow block ack response without data When FW fails to get block ack, it will send the notification with 0 items in the TFD queue elements. Allow this and handle accordingly. Fixes: c46e7724bfe9 ("iwlwifi: mvm: support new BA notification response") Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ed7ee50046459..8f737f6cdd80b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1785,6 +1785,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ba_info.status.status_driver_data[0] = (void *)(uintptr_t)ba_res->reduced_txp; + if (!le16_to_cpu(ba_res->tfd_cnt)) + goto out; + /* * TODO: * When supporting multi TID aggregations - we need to move @@ -1802,6 +1805,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) le16_to_cpu(ba_res->tfd[0].tfd_index), &ba_info, le32_to_cpu(ba_res->tx_rate)); +out: IWL_DEBUG_TX_REPLY(mvm, "BA_NOTIFICATION Received from sta_id = %d, flags %x, sent:%d, acked:%d\n", sta_id, le32_to_cpu(ba_res->flags), From 97b00d877bb8c2e499b9d0c07b65bd92b4e91ddd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 10:26:02 +0200 Subject: [PATCH 153/201] iwlwifi: pcie: fix mutex leak in gen2 start If the context info fails to be allocated, the mutex isn't unlocked properly, fix that. Fixes: eda50cde58de ("iwlwifi: pcie: add context information support") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index ef8f563a48d94..ac60a282d6deb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -359,8 +359,9 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, goto out; } - if (iwl_pcie_ctxt_info_init(trans, fw)) - return -ENOMEM; + ret = iwl_pcie_ctxt_info_init(trans, fw); + if (ret) + goto out; /* re-check RF-Kill state since we may have missed the interrupt */ hw_rfkill = iwl_trans_check_hw_rf_kill(trans); From 718ceb22a0ccd0b3a02a4bd401d944a1eb16f3ce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2017 10:30:47 +0200 Subject: [PATCH 154/201] iwlwifi: pcie: free context info in case of failures If iwl_pcie_ctxt_info_init_fw_sec() fails, the previous allocated DMA memory needs to be freed (it even goes out of scope immediately.) Do that to prevent the leak. Fixes: eda50cde58de ("iwlwifi: pcie: add context information support") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 854d61888f4df..1d95512361b2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -241,8 +241,11 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info); - if (ret) + if (ret) { + dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info), + ctxt_info, trans_pcie->ctxt_info_dma_addr); return ret; + } trans_pcie->ctxt_info = ctxt_info; From 7e2f18f06408ff56d7f75e68de8064777137b319 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 5 Apr 2017 15:26:40 -0700 Subject: [PATCH 155/201] mwifiex: MAC randomization should not be persistent nl80211 provides the NL80211_SCAN_FLAG_RANDOM_ADDR for every scan request that should be randomized; the absence of such a flag means we should not randomize. However, mwifiex was stashing the latest randomization request and *always* using it for future scans, even those that didn't set the flag. Let's zero out the randomization info whenever we get a scan request without NL80211_SCAN_FLAG_RANDOM_ADDR. I'd prefer to remove priv->random_mac entirely (and plumb the randomization MAC properly through the call sequence), but the spaghetti is a little difficult to unravel here for me. Fixes: c2a8f0ff9c6c ("mwifiex: support random MAC address for scanning") Cc: # 4.9+ Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 44d06177859e7..4107663130657 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -2547,9 +2547,11 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, priv->random_mac[i] |= get_random_int() & ~(request->mac_addr_mask[i]); } + ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); + } else { + eth_zero_addr(priv->random_mac); } - ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); user_scan_cfg->num_ssids = request->n_ssids; user_scan_cfg->ssid_list = request->ssids; From 625b4dba57b256943a1714c7783e3cfbb52ce5c3 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 13 Apr 2017 06:48:19 +0000 Subject: [PATCH 156/201] mwifiex: remove unnecessary wakeup interrupt number sanity check If wakeup interrupt handler is called, we know that the wakeup interrupt number is valid, there is no need to check it. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Reviewed-by: Dmitry Torokhov Reviewed-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 912b687f46715..3d59d74c7f997 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1514,11 +1514,9 @@ static irqreturn_t mwifiex_irq_wakeup_handler(int irq, void *priv) { struct mwifiex_adapter *adapter = priv; - if (adapter->irq_wakeup >= 0) { - dev_dbg(adapter->dev, "%s: wake by wifi", __func__); - adapter->wake_by_wifi = true; - disable_irq_nosync(irq); - } + dev_dbg(adapter->dev, "%s: wake by wifi", __func__); + adapter->wake_by_wifi = true; + disable_irq_nosync(irq); /* Notify PM core we are wakeup source */ pm_wakeup_event(adapter->dev, 0); From ef6c7d3cb731e3aa6a4ce8d501b97df73ea40b4e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 13 Apr 2017 06:48:20 +0000 Subject: [PATCH 157/201] mwifiex: fall back mwifiex_dbg to pr_info when adapter->dev not set mwifiex_dbg will do nothing before adapter->dev get assigned. several logs lost in this case. it can be avoided by fall back to pr_info. Signed-off-by: Xinming Hu Reviewed-by: Brian Norris Reviewed-by: Dmitry Torokhov Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 3d59d74c7f997..cd21bbf4412f7 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1753,7 +1753,7 @@ void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask, struct va_format vaf; va_list args; - if (!adapter->dev || !(adapter->debug_mask & mask)) + if (!(adapter->debug_mask & mask)) return; va_start(args, fmt); @@ -1761,7 +1761,10 @@ void _mwifiex_dbg(const struct mwifiex_adapter *adapter, int mask, vaf.fmt = fmt; vaf.va = &args; - dev_info(adapter->dev, "%pV", &vaf); + if (adapter->dev) + dev_info(adapter->dev, "%pV", &vaf); + else + pr_info("%pV", &vaf); va_end(args); } From 127ee1db09707856dc4915afc60886561644585d Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 13 Apr 2017 06:48:21 +0000 Subject: [PATCH 158/201] mwifiex: pcie: correct scratch register name This patch correct pcie scratch register name, to keep the same with chipset side definition. Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 4 ++-- drivers/net/wireless/marvell/mwifiex/pcie.h | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 92ffb1ba17e61..061223149bedd 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -2494,8 +2494,8 @@ mwifiex_pcie_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; int pcie_scratch_reg[] = {PCIE_SCRATCH_12_REG, - PCIE_SCRATCH_13_REG, - PCIE_SCRATCH_14_REG}; + PCIE_SCRATCH_14_REG, + PCIE_SCRATCH_15_REG}; if (!p) return 0; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 00e8ee5ad4a83..7e2450ce79d33 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -77,8 +77,9 @@ #define PCIE_SCRATCH_10_REG 0xCE8 #define PCIE_SCRATCH_11_REG 0xCEC #define PCIE_SCRATCH_12_REG 0xCF0 -#define PCIE_SCRATCH_13_REG 0xCF8 -#define PCIE_SCRATCH_14_REG 0xCFC +#define PCIE_SCRATCH_13_REG 0xCF4 +#define PCIE_SCRATCH_14_REG 0xCF8 +#define PCIE_SCRATCH_15_REG 0xCFC #define PCIE_RD_DATA_PTR_Q0_Q1 0xC08C #define PCIE_WR_DATA_PTR_Q0_Q1 0xC05C @@ -217,8 +218,8 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, - .fw_dump_ctrl = 0xcf4, - .fw_dump_start = 0xcf8, + .fw_dump_ctrl = PCIE_SCRATCH_13_REG, + .fw_dump_start = PCIE_SCRATCH_14_REG, .fw_dump_end = 0xcff, .fw_dump_host_ready = 0xee, .fw_dump_read_done = 0xfe, @@ -254,8 +255,8 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = { .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, .pfu_enabled = 1, .sleep_cookie = 0, - .fw_dump_ctrl = 0xcf4, - .fw_dump_start = 0xcf8, + .fw_dump_ctrl = PCIE_SCRATCH_13_REG, + .fw_dump_start = PCIE_SCRATCH_14_REG, .fw_dump_end = 0xcff, .fw_dump_host_ready = 0xcc, .fw_dump_read_done = 0xdd, From efde6648a618025a8fe1bc550d7ba569e44dc2fe Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Thu, 13 Apr 2017 13:10:33 -0700 Subject: [PATCH 159/201] mwifiex: pcie: extract wifi part from combo firmware during function level reset A separate wifi-only firmware was download during pcie function level reset. It is in fact the tail part of wifi/bt combo firmware. Per Brian's and Dmitry's suggestion, this patch extract the wifi part from combo firmware. After that, the mrvl/pcie8997_wlan_v4.bin image in linux-firmware repo is redundant (though I guess we keep it around to support older kernels). Signed-off-by: Xinming Hu Signed-off-by: Ganapathi Bhat Signed-off-by: Cathy Luo Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/fw.h | 18 ++++ drivers/net/wireless/marvell/mwifiex/pcie.c | 114 ++++++++++++++++++-- drivers/net/wireless/marvell/mwifiex/pcie.h | 3 +- 3 files changed, 127 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 0b683742e30cd..6cf9ab9133ea3 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -43,6 +43,24 @@ struct tx_packet_hdr { struct rfc_1042_hdr rfc1042_hdr; } __packed; +struct mwifiex_fw_header { + __le32 dnld_cmd; + __le32 base_addr; + __le32 data_length; + __le32 crc; +} __packed; + +struct mwifiex_fw_data { + struct mwifiex_fw_header header; + __le32 seq_num; + u8 data[1]; +} __packed; + +#define MWIFIEX_FW_DNLD_CMD_1 0x1 +#define MWIFIEX_FW_DNLD_CMD_5 0x5 +#define MWIFIEX_FW_DNLD_CMD_6 0x6 +#define MWIFIEX_FW_DNLD_CMD_7 0x7 + #define B_SUPPORTED_RATES 5 #define G_SUPPORTED_RATES 9 #define BG_SUPPORTED_RATES 13 diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 061223149bedd..63102efb388e4 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1956,6 +1956,94 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, return ret; } +/* Combo firmware image is a combination of + * (1) combo crc heaer, start with CMD5 + * (2) bluetooth image, start with CMD7, end with CMD6, data wrapped in CMD1. + * (3) wifi image. + * + * This function bypass the header and bluetooth part, return + * the offset of tail wifi-only part. + */ + +static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, + const void *firmware, u32 firmware_len) { + const struct mwifiex_fw_data *fwdata; + u32 offset = 0, data_len, dnld_cmd; + int ret = 0; + bool cmd7_before = false; + + while (1) { + /* Check for integer and buffer overflow */ + if (offset + sizeof(fwdata->header) < sizeof(fwdata->header) || + offset + sizeof(fwdata->header) >= firmware_len) { + mwifiex_dbg(adapter, ERROR, + "extract wifi-only fw failure!\n"); + ret = -1; + goto done; + } + + fwdata = firmware + offset; + dnld_cmd = le32_to_cpu(fwdata->header.dnld_cmd); + data_len = le32_to_cpu(fwdata->header.data_length); + + /* Skip past header */ + offset += sizeof(fwdata->header); + + switch (dnld_cmd) { + case MWIFIEX_FW_DNLD_CMD_1: + if (!cmd7_before) { + mwifiex_dbg(adapter, ERROR, + "no cmd7 before cmd1!\n"); + ret = -1; + goto done; + } + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + break; + case MWIFIEX_FW_DNLD_CMD_5: + /* Check for integer overflow */ + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + break; + case MWIFIEX_FW_DNLD_CMD_6: + /* Check for integer overflow */ + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + ret = -1; + goto done; + } + offset += data_len; + if (offset >= firmware_len) { + mwifiex_dbg(adapter, ERROR, + "extract wifi-only fw failure!\n"); + ret = -1; + } else { + ret = offset; + } + goto done; + case MWIFIEX_FW_DNLD_CMD_7: + cmd7_before = true; + break; + default: + mwifiex_dbg(adapter, ERROR, "unknown dnld_cmd %d\n", + dnld_cmd); + ret = -1; + goto done; + } + } + +done: + return ret; +} + /* * This function downloads the firmware to the card. * @@ -1971,7 +2059,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, u32 firmware_len = fw->fw_len; u32 offset = 0; struct sk_buff *skb; - u32 txlen, tx_blocks = 0, tries, len; + u32 txlen, tx_blocks = 0, tries, len, val; u32 block_retry_cnt = 0; struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; @@ -1998,6 +2086,24 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, goto done; } + ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_13_REG, &val); + if (ret) { + mwifiex_dbg(adapter, FATAL, "Failed to read scratch register 13\n"); + goto done; + } + + /* PCIE FLR case: extract wifi part from combo firmware*/ + if (val == MWIFIEX_PCIE_FLR_HAPPENS) { + ret = mwifiex_extract_wifi_fw(adapter, firmware, firmware_len); + if (ret < 0) { + mwifiex_dbg(adapter, ERROR, "Failed to extract wifi fw\n"); + goto done; + } + offset = ret; + mwifiex_dbg(adapter, MSG, + "info: dnld wifi firmware from %d bytes\n", offset); + } + /* Perform firmware data transfer */ do { u32 ireg_intr = 0; @@ -3070,12 +3176,6 @@ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) struct pci_dev *pdev = card->dev; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - /* Bluetooth is not on pcie interface. Download Wifi only firmware - * during pcie FLR, so that bluetooth part of firmware which is - * already running doesn't get affected. - */ - strcpy(adapter->fw_name, PCIE8997_DEFAULT_WIFIFW_NAME); - /* tx_buf_size might be changed to 3584 by firmware during * data transfer, we should reset it to default size. */ diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 7e2450ce79d33..f7ce9b6db6b41 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -35,7 +35,6 @@ #define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin" #define PCIEUART8997_FW_NAME_V4 "mrvl/pcieuart8997_combo_v4.bin" #define PCIEUSB8997_FW_NAME_V4 "mrvl/pcieusb8997_combo_v4.bin" -#define PCIE8997_DEFAULT_WIFIFW_NAME "mrvl/pcie8997_wlan_v4.bin" #define PCIE_VENDOR_ID_MARVELL (0x11ab) #define PCIE_VENDOR_ID_V2_MARVELL (0x1b4b) @@ -120,6 +119,8 @@ #define MWIFIEX_SLEEP_COOKIE_SIZE 4 #define MWIFIEX_MAX_DELAY_COUNT 100 +#define MWIFIEX_PCIE_FLR_HAPPENS 0xFEDCBABA + struct mwifiex_pcie_card_reg { u16 cmd_addr_lo; u16 cmd_addr_hi; From 3c8cb9ad032d737b874e402c59eb51e3c991a144 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Apr 2017 14:51:17 -0700 Subject: [PATCH 160/201] mwifiex: pcie: fix cmd_buf use-after-free in remove/reset Command buffers (skb's) are allocated by the main driver, and freed upon the last use. That last use is often in mwifiex_free_cmd_buffer(). In the meantime, if the command buffer gets used by the PCI driver, we map it as DMA-able, and store the mapping information in the 'cb' memory. However, if a command was in-flight when resetting the device (and therefore was still mapped), we don't get a chance to unmap this memory until after the core has cleaned up its command handling. Let's keep a refcount within the PCI driver, so we ensure the memory only gets freed after we've finished unmapping it. Noticed by KASAN when forcing a reset via: echo 1 > /sys/bus/pci/.../reset The same code path can presumably be exercised in remove() and shutdown(). [ 205.390377] mwifiex_pcie 0000:01:00.0: info: shutdown mwifiex... [ 205.400393] ================================================================== [ 205.407719] BUG: KASAN: use-after-free in mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] at addr ffffffc0ad471b28 [ 205.419040] Read of size 16 by task bash/1913 [ 205.423421] ============================================================================= [ 205.431625] BUG skbuff_head_cache (Tainted: G B ): kasan: bad access detected [ 205.439815] ----------------------------------------------------------------------------- [ 205.439815] [ 205.449534] INFO: Allocated in __build_skb+0x48/0x114 age=1311 cpu=4 pid=1913 [ 205.456709] alloc_debug_processing+0x124/0x178 [ 205.461282] ___slab_alloc.constprop.58+0x528/0x608 [ 205.466196] __slab_alloc.isra.54.constprop.57+0x44/0x54 [ 205.471542] kmem_cache_alloc+0xcc/0x278 [ 205.475497] __build_skb+0x48/0x114 [ 205.479019] __netdev_alloc_skb+0xe0/0x170 [ 205.483244] mwifiex_alloc_cmd_buffer+0x68/0xdc [mwifiex] [ 205.488759] mwifiex_init_fw+0x40/0x6cc [mwifiex] [ 205.493584] _mwifiex_fw_dpc+0x158/0x520 [mwifiex] [ 205.498491] mwifiex_reinit_sw+0x2c4/0x398 [mwifiex] [ 205.503510] mwifiex_pcie_reset_notify+0x114/0x15c [mwifiex_pcie] [ 205.509643] pci_reset_notify+0x5c/0x6c [ 205.513519] pci_reset_function+0x6c/0x7c [ 205.517567] reset_store+0x68/0x98 [ 205.521003] dev_attr_store+0x54/0x60 [ 205.524705] sysfs_kf_write+0x9c/0xb0 [ 205.528413] INFO: Freed in __kfree_skb+0xb0/0xbc age=131 cpu=4 pid=1913 [ 205.535064] free_debug_processing+0x264/0x370 [ 205.539550] __slab_free+0x84/0x40c [ 205.543075] kmem_cache_free+0x1c8/0x2a0 [ 205.547030] __kfree_skb+0xb0/0xbc [ 205.550465] consume_skb+0x164/0x178 [ 205.554079] __dev_kfree_skb_any+0x58/0x64 [ 205.558304] mwifiex_free_cmd_buffer+0xa0/0x158 [mwifiex] [ 205.563817] mwifiex_shutdown_drv+0x578/0x5c4 [mwifiex] [ 205.569164] mwifiex_shutdown_sw+0x178/0x310 [mwifiex] [ 205.574353] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] [ 205.580398] pci_reset_notify+0x5c/0x6c [ 205.584274] pci_dev_save_and_disable+0x24/0x6c [ 205.588837] pci_reset_function+0x30/0x7c [ 205.592885] reset_store+0x68/0x98 [ 205.596324] dev_attr_store+0x54/0x60 [ 205.600017] sysfs_kf_write+0x9c/0xb0 ... [ 205.800488] Call trace: [ 205.802980] [] dump_backtrace+0x0/0x190 [ 205.808415] [] show_stack+0x20/0x28 [ 205.813506] [] dump_stack+0xa4/0xcc [ 205.818598] [] print_trailer+0x158/0x168 [ 205.824120] [] object_err+0x4c/0x5c [ 205.829210] [] kasan_report+0x334/0x500 [ 205.834641] [] check_memory_region+0x20/0x14c [ 205.840593] [] __asan_loadN+0x14/0x1c [ 205.845879] [] mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] [ 205.854282] [] mwifiex_pcie_delete_cmdrsp_buf+0x94/0xa8 [mwifiex_pcie] [ 205.862421] [] mwifiex_pcie_free_buffers+0x11c/0x158 [mwifiex_pcie] [ 205.870302] [] mwifiex_pcie_down_dev+0x70/0x80 [mwifiex_pcie] [ 205.877736] [] mwifiex_shutdown_sw+0x190/0x310 [mwifiex] [ 205.884658] [] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] [ 205.892446] [] pci_reset_notify+0x5c/0x6c [ 205.898048] [] pci_dev_save_and_disable+0x24/0x6c [ 205.904350] [] pci_reset_function+0x30/0x7c [ 205.910134] [] reset_store+0x68/0x98 [ 205.915312] [] dev_attr_store+0x54/0x60 [ 205.920750] [] sysfs_kf_write+0x9c/0xb0 [ 205.926182] [] kernfs_fop_write+0x184/0x1f8 [ 205.931963] [] __vfs_write+0x6c/0x17c [ 205.937221] [] vfs_write+0xf0/0x1c4 [ 205.942310] [] SyS_write+0x78/0xd8 [ 205.947312] [] el0_svc_naked+0x24/0x28 ... [ 205.998268] ================================================================== This bug has been around in different forms for a while. It was sort of noticed in commit 955ab095c51a ("mwifiex: Do not kfree cmd buf while unregistering PCIe"), but it just fixed the double-free, without acknowledging the potential for use-after-free. Fixes: fc3314609047 ("mwifiex: use pci_alloc/free_consistent APIs for PCIe") Cc: Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 63102efb388e4..d44bd3faed0ea 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1035,6 +1035,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) if (card && card->cmd_buf) { mwifiex_unmap_pci_memory(adapter, card->cmd_buf, PCI_DMA_TODEVICE); + dev_kfree_skb_any(card->cmd_buf); } return 0; } @@ -1601,6 +1602,11 @@ mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) return -1; card->cmd_buf = skb; + /* + * Need to keep a reference, since core driver might free up this + * buffer before we've unmapped it. + */ + skb_get(skb); /* To send a command, the driver will: 1. Write the 64bit physical address of the data buffer to @@ -1703,6 +1709,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) if (card->cmd_buf) { mwifiex_unmap_pci_memory(adapter, card->cmd_buf, PCI_DMA_TODEVICE); + dev_kfree_skb_any(card->cmd_buf); card->cmd_buf = NULL; } From 9ae3fbd109d9d89c442a3412e41fc532a9829ea8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Apr 2017 14:51:18 -0700 Subject: [PATCH 161/201] mwifiex: reset timeout flag when resetting device If we reset because of a command timeout, we should reset this flag. Otherwise, we might erroneously think the next command after reset is timing out, and trigger another reset. The above behavior effectively neuters the automatic card_reset() behavior, as it means we will never recover from a command timeout properly (and in fact, we might enter an infinite loop: timeout -> reset -> (fake) timeout -> reset -> ... This fixes a bug introduced with introduction of PCIe function level reset support, but it was carried into the SDIO driver when it was converted to use the same codepaths. And this is currently mostly a problem only in the SDIO driver, because it's the only one with automatic card_reset() support (e.g., on command timeout). But it will be a problem for PCIe too, as I'm working on supporting automatic card_reset() for PCIe. Fixes: c742e623e941 ("mwifiex: sdio card reset enhancement") Fixes: 4c5dae59d2e9 ("mwifiex: add PCIe function level reset support") Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index cd21bbf4412f7..fdeb0bbb884c5 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1441,6 +1441,7 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter) init_waitqueue_head(&adapter->init_wait_q); adapter->is_suspended = false; adapter->hs_activated = false; + adapter->is_cmd_timedout = 0; init_waitqueue_head(&adapter->hs_activate_wait_q); init_waitqueue_head(&adapter->cmd_wait_q.wait); adapter->cmd_wait_q.status = 0; From 35e67d3d58b955fe35d78ce439b4fa996a9eadcd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Apr 2017 14:51:19 -0700 Subject: [PATCH 162/201] mwifiex: pcie: clear outstanding work when resetting When we shut down the device (i.e., during 'reset'), we cancel any outstanding work, but we don't clear any work-related flags. This can cause problems if, e.g., we begin to queue a new firmware dump or card reset while the other one is in progress. That might leave work_flags with a stale value, and we might begin one of these *after* we've completely reset the device. That doesn't make sense, because all firmware context will have been lost by then. This fixes some forms of cascading failures, where I: (a) force a firmware dump (cat /sys/kernel/debug/mwifiex/mlan0/device_dump) (b) run a Wifi scan in parallel (iw mlan0 scan) (c) the scan times out due to (a) hogging the interface (d) the command timeout triggers another firmware dump and a reset [*] (e) the 2nd firmware dump flag persists across the reset (f) as soon as the interface comes back up, we trigger the pending firmware dump (g) subsequent commands time out again, while we are processing the firmware dump; return to (d) [*] Note that automatic card_reset() support is not yet implemented for the mwifiex PCIe driver, so we won't hit *exactly* this behavior yet. But we can see similarly-confusing behaviors today. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index d44bd3faed0ea..ac62bce50e964 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -371,6 +371,8 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) */ mwifiex_shutdown_sw(adapter); adapter->surprise_removed = true; + clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); } else { /* Kernel stores and restores PCIe function context before and * after performing FLR respectively. Reconfigure the software From fb9e67bee3ab7111513130c516ffe378d885c0d0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Apr 2017 14:51:20 -0700 Subject: [PATCH 163/201] mwifiex: don't leak 'chan_stats' on reset 'chan_stats' is (re)allocated in _mwifiex_fw_dpc() -> mwifiex_init_channel_scan_gap(), which is called whenever the device is initialized -- at probe or at reset. But we only free it in we completely unregister the adapter, meaning we leak a copy of it during every reset. Let's free it in the shutdown / removal paths instead (and in the error-handling path), to avoid the leak. Ideally, we can eventually unify much of mwifiex_shutdown_sw() and mwifiex_remove_card() (way too much copy-and-paste) to reduce the burden on bugfixes like this. But that's work for tomorrow. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index fdeb0bbb884c5..739d654bc9a61 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -149,7 +149,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) kfree(adapter->regd); - vfree(adapter->chan_stats); kfree(adapter); return 0; } @@ -633,6 +632,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); err_init_fw: @@ -1417,6 +1417,7 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); exit_return: @@ -1726,6 +1727,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); From bf30171b22c56567d44117592ec376aef1e47a6f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 19 Apr 2017 10:12:35 -0700 Subject: [PATCH 164/201] MAINTAINERS: update Amitkumar's email address His email is bouncing, and he'd like to use this new one. Cc: Amitkumar Karwar Cc: Nishant Sarmukadam Cc: Ganapathi Bhat Cc: Xinming Hu Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5397f54af5fc4..2efb7df5f879c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7857,7 +7857,7 @@ S: Maintained F: drivers/net/ethernet/marvell/mvneta.* MARVELL MWIFIEX WIRELESS DRIVER -M: Amitkumar Karwar +M: Amitkumar Karwar M: Nishant Sarmukadam M: Ganapathi Bhat M: Xinming Hu From 930d2bf242d6abdfe8226a3b585007127fbb0f99 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:52 -0500 Subject: [PATCH 165/201] rtlwifi: btcoex: 21a 2ant: limit rx aggregation size to avoid bt interrupt Larger packets have higher opportunity to be interrupt by bt signal. In order to shorten the transmission time, control the packet aggregation size. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index f36dab9291b11..3e671d409e61e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -244,6 +244,27 @@ static u8 btc8821a2ant_wifi_rssi_state(struct btc_coexist *btcoexist, return wifi_rssi_state; } +static +void btc8821a2ant_limited_rx(struct btc_coexist *btcoexist, bool force_exec, + bool rej_ap_agg_pkt, bool bt_ctrl_agg_buf_size, + u8 agg_buf_size) +{ + bool reject_rx_agg = rej_ap_agg_pkt; + bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* Rx Aggregation related setting */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, works when BT control Rx aggregation size */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + static void btc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1141,6 +1162,8 @@ static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) low_pwr_disable = true; btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Wifi IPS + BT LPS!!\n"); @@ -1447,6 +1470,7 @@ static void btc8821a2ant_action_sco(struct btc_coexist *btcoexist) 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); if (BTC_RSSI_HIGH(bt_rssi_state)) @@ -1526,6 +1550,7 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) @@ -1816,6 +1841,7 @@ static void btc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); @@ -1959,6 +1985,7 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) @@ -2038,6 +2065,7 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) From 4776d349071d6cf85886e85721f71599b832bf72 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:53 -0500 Subject: [PATCH 166/201] rtlwifi: btcoex: 21a 2ant: monitor if bt is slave or not We monitor the packet counter to guess if the bt is slave or not, and when bt is slave, it may receive packet at any time, so we will have to take care about it Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 3e671d409e61e..7f685a02d8659 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -268,6 +268,7 @@ void btc8821a2ant_limited_rx(struct btc_coexist *btcoexist, bool force_exec, static void btc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; u32 reg_hp_txrx, reg_lp_txrx, u4tmp; u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; @@ -287,6 +288,13 @@ static void btc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) coex_sta->low_priority_tx = reg_lp_tx; coex_sta->low_priority_rx = reg_lp_rx; + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) && + (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); From eebc58782eff0253934b834934ab5ba385e5390e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:54 -0500 Subject: [PATCH 167/201] rtlwifi: btcoex: 21a 2ant: monitor wifi counter to check network status If there are a lot of low-rate packets, then the connection of wifi is unstable. If so, we should switch resource to bt to have a higher transmission quality, or wifi resource will be wasted Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 38 +++++++++++++++++++ .../rtlwifi/btcoexist/halbtc8821a2ant.h | 10 +++++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 7f685a02d8659..e23670a23e4d2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -306,6 +306,43 @@ static void btc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); } +static void btc8821a2ant_monitor_wifi_ctr(struct btc_coexist *btcoexist) +{ + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf88); + coex_sta->crc_ok_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf94); + coex_sta->crc_ok_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf90); + coex_sta->crc_ok_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfb8); + + coex_sta->crc_err_cck = + btcoexist->btc_read_4byte(btcoexist, 0xf84); + coex_sta->crc_err_11g = + btcoexist->btc_read_2byte(btcoexist, 0xf96); + coex_sta->crc_err_11n = + btcoexist->btc_read_2byte(btcoexist, 0xf92); + coex_sta->crc_err_11n_agg = + btcoexist->btc_read_2byte(btcoexist, 0xfba); + } + + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x0); +} + static void btc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2888,4 +2925,5 @@ void ex_btc8821a2ant_periodical(struct btc_coexist *btcoexist) btc8821a2ant_query_bt_info(btcoexist); btc8821a2ant_monitor_bt_ctr(btcoexist); + btc8821a2ant_monitor_wifi_ctr(btcoexist); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index b4cf1f53d5105..ce8e0d719e78a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -141,6 +141,16 @@ struct coex_sta_8821a_2ant { bool c2h_bt_inquiry_page; u8 bt_retry_cnt; u8 bt_info_ext; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; }; /*=========================================== From 4b1f6eaac344ed0895a9ed5dc71b4f6945e255ca Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:55 -0500 Subject: [PATCH 168/201] rtlwifi: btcoex: 21a 2ant: update bt profiling information This function updates the information of bt profiling to help us decide the network status and dispatch the resource properly. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index e23670a23e4d2..a9ce79d7f4b41 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -359,6 +359,54 @@ static void btc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } +static void btc8821a2ant_update_bt_link_info(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + static u8 btc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -2856,8 +2904,7 @@ void ex_btc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE; } - if (bt_hs_on) - coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + btc8821a2ant_update_bt_link_info(btcoexist); } if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status) From aed6b11e4fc2134ccd4db4d1a41b2cc8fed980f3 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:56 -0500 Subject: [PATCH 169/201] rtlwifi: btcoex: 21a 2ant: finer adjustment of bt power Originally we only increase/decrease bt power in a fixed power gap, this patch makes us be able to modify bt power for multiple power gaps and we can precisely adjust the bt power. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 51 +++++++++---------- .../rtlwifi/btcoexist/halbtc8821a2ant.h | 4 +- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index a9ce79d7f4b41..a074d480166d0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -617,45 +617,42 @@ static void btc8821a2ant_set_fw_dac_swing_lvl(struct btc_coexist *btcoexist, } static void btc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, - bool dec_bt_pwr) + u8 dec_bt_pwr_lvl) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 h2c_parameter[1] = {0}; - h2c_parameter[0] = 0; - - if (dec_bt_pwr) - h2c_parameter[0] |= BIT1; + h2c_parameter[0] = dec_bt_pwr_lvl; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n", - (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + "[BTCoex], decrease Bt Power Level : %u, FW write 0x62 = 0x%x\n", + dec_bt_pwr_lvl, h2c_parameter[0]); btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); } static void btc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist, - bool force_exec, bool dec_bt_pwr) + bool force_exec, u8 dec_bt_pwr_lvl) { struct rtl_priv *rtlpriv = btcoexist->adapter; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], %s Dec BT power = %s\n", - (force_exec ? "force to" : ""), - ((dec_bt_pwr) ? "ON" : "OFF")); - coex_dm->cur_dec_bt_pwr = dec_bt_pwr; + "[BTCoex], %s Dec BT power level = %u\n", + (force_exec ? "force to" : ""), dec_bt_pwr_lvl); + coex_dm->cur_dec_bt_pwr_lvl = dec_bt_pwr_lvl; if (!force_exec) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], pre_dec_bt_pwr = %d, cur_dec_bt_pwr = %d\n", - coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + "[BTCoex], pre_dec_bt_pwr_lvl = %d, cur_dec_bt_pwr_lvl = %d\n", + coex_dm->pre_dec_bt_pwr_lvl, + coex_dm->cur_dec_bt_pwr_lvl); - if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + if (coex_dm->pre_dec_bt_pwr_lvl == coex_dm->cur_dec_bt_pwr_lvl) return; } - btc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + btc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr_lvl); - coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; + coex_dm->pre_dec_bt_pwr_lvl = coex_dm->cur_dec_bt_pwr_lvl; } static void btc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, @@ -1149,7 +1146,7 @@ static void btc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) /* fw all off */ btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); /* sw all off */ btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); @@ -1173,7 +1170,7 @@ static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) btc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); @@ -1263,7 +1260,7 @@ static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); @@ -1792,9 +1789,9 @@ static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); @@ -2007,9 +2004,9 @@ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); @@ -2162,9 +2159,9 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); @@ -2608,7 +2605,7 @@ void ex_btc8821a2ant_display_coex_info(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", - coex_dm->cur_dec_bt_pwr, + coex_dm->cur_dec_bt_pwr_lvl, coex_dm->cur_ignore_wlan_act); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index ce8e0d719e78a..ee5aa188af554 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -69,8 +69,8 @@ enum _BT_8821A_2ANT_COEX_ALGO { struct coex_dm_8821a_2ant { /* fw mechanism */ - bool pre_dec_bt_pwr; - bool cur_dec_bt_pwr; + bool pre_dec_bt_pwr_lvl; + bool cur_dec_bt_pwr_lvl; bool pre_bt_lna_constrain; bool cur_bt_lna_constrain; u8 pre_bt_psd_mode; From 7cc7f1a18bccea1e278045b133d91265baa3eb11 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:57 -0500 Subject: [PATCH 170/201] rtlwifi: btcoex: 21a 2ant: move from bt_stack_info to bt_link_info Gather variables to the 8821a2ant coex structure. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 112 +++++++++--------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index a074d480166d0..4abfddcf2d11e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -410,50 +410,43 @@ static void btc8821a2ant_update_bt_link_info(struct btc_coexist *btcoexist) static u8 btc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool bt_hs_on = false; u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED; u8 num_of_diff_profile = 0; btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); - /* sync BTInfo with BT firmware and stack */ - if (!stack_info->hid_exist) - stack_info->hid_exist = coex_sta->hid_exist; - /* when stack HID report error, here we use the info from bt fw. */ - if (!stack_info->bt_link_exist) - stack_info->bt_link_exist = coex_sta->bt_link_exist; - - if (!coex_sta->bt_link_exist) { + if (!bt_link_info->bt_link_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], No profile exists!!!\n"); + "[BTCoex], No BT link exists!!!\n"); return algorithm; } - if (coex_sta->sco_exist) + if (bt_link_info->sco_exist) num_of_diff_profile++; - if (coex_sta->hid_exist) + if (bt_link_info->hid_exist) num_of_diff_profile++; - if (coex_sta->pan_exist) + if (bt_link_info->pan_exist) num_of_diff_profile++; - if (coex_sta->a2dp_exist) + if (bt_link_info->a2dp_exist) num_of_diff_profile++; if (num_of_diff_profile == 1) { - if (coex_sta->sco_exist) { + if (bt_link_info->sco_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO only\n"); algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } else { - if (coex_sta->hid_exist) { + if (bt_link_info->hid_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID only\n"); algorithm = BT_8821A_2ANT_COEX_ALGO_HID; - } else if (coex_sta->a2dp_exist) { + } else if (bt_link_info->a2dp_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], A2DP only\n"); algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP; - } else if (coex_sta->pan_exist) { + } else if (bt_link_info->pan_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -468,16 +461,16 @@ static u8 btc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) } } } else if (num_of_diff_profile == 2) { - if (coex_sta->sco_exist) { - if (coex_sta->hid_exist) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + HID\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; - } else if (coex_sta->a2dp_exist) { + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + A2DP ==> SCO\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; - } else if (coex_sta->pan_exist) { + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -487,99 +480,104 @@ static u8 btc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + PAN(EDR)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } } } else { - if (coex_sta->hid_exist && - coex_sta->a2dp_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID + A2DP\n"); algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; - } else if (coex_sta->hid_exist && - coex_sta->pan_exist) { + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID + PAN(HS)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID + PAN(EDR)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; } - } else if (coex_sta->pan_exist && - coex_sta->a2dp_exist) { + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], A2DP + PAN(HS)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; + algorithm = + BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], A2DP + PAN(EDR)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP; + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP; } } } } else if (num_of_diff_profile == 3) { - if (coex_sta->sco_exist) { - if (coex_sta->hid_exist && - coex_sta->a2dp_exist) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + HID + A2DP ==> HID\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; - } else if (coex_sta->hid_exist && - coex_sta->pan_exist) { + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + HID + PAN(HS)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + HID + PAN(EDR)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } - } else if (coex_sta->pan_exist && - coex_sta->a2dp_exist) { + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + A2DP + PAN(HS)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } } } else { - if (coex_sta->hid_exist && - coex_sta->pan_exist && - coex_sta->a2dp_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID + A2DP + PAN(HS)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + algorithm = + BT_8821A_2ANT_COEX_ALGO_HID_A2DP; } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], HID + A2DP + PAN(EDR)\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + algorithm = + BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; } } } } else if (num_of_diff_profile >= 3) { - if (coex_sta->sco_exist) { - if (coex_sta->hid_exist && - coex_sta->pan_exist && - coex_sta->a2dp_exist) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { if (bt_hs_on) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -589,7 +587,7 @@ static u8 btc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); - algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; } } } From 5a81969c1cc3a19a65ebbd9f31f844b0a5060d25 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:58 -0500 Subject: [PATCH 171/201] rtlwifi: btcoex: 21a 2ant: suffer less tx penalty from retry Change h2c parameter to decrease tx penalty. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 4abfddcf2d11e..1a1e4136d48e3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -693,11 +693,11 @@ static void btc8821a2ant_set_sw_penalty_tx_rate_adaptive( /* normal rate except MCS7/6/5, OFDM54/48/36 */ h2c_parameter[2] = 0x00; /* MCS7 or OFDM54 */ - h2c_parameter[3] = 0xf7; + h2c_parameter[3] = 0xf5; /* MCS6 or OFDM48 */ - h2c_parameter[4] = 0xf8; + h2c_parameter[4] = 0xa0; /* MCS5 or OFDM36 */ - h2c_parameter[5] = 0xf9; + h2c_parameter[5] = 0xa0; } RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, From d9158ea1d1bde5f01c03fa92f3a88b7fb39153e4 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:06:59 -0500 Subject: [PATCH 172/201] rtlwifi: btcoex: 21a 2ant: check power save state before pstdma The power_save_state function checks the state of power saving. For tdma settings, the wifi sends nullfunc to pretend enter power saving and then bt can transmit. Hence the coex needs to check the power status before set the pstdma function. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 119 +++++++++++++++--- .../rtlwifi/btcoexist/halbtc8821a2ant.h | 5 + 2 files changed, 104 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 1a1e4136d48e3..36e722a33f0f2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -872,6 +872,33 @@ static void btc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex, btcoex->btc_fill_h2c(btcoex, 0x63, 1, h2c_parameter); } +static void btc8821a2ant_set_lps_rpwm(struct btc_coexist *btcoexist, u8 lps_val, + u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +static void btc8821a2ant_lps_rpwm(struct btc_coexist *btcoexist, + bool force_exec, u8 lps_val, u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + btc8821a2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + static void btc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist, bool force_exec, bool enable) { @@ -1139,9 +1166,75 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } +static void +btc8821a2ant_ps_tdma_check_for_power_save_state(struct btc_coexist *btcoexist, + bool new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { + /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing */ + } else { + /* will leave LPS state, turn off psTdma first */ + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + } else { + /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } else { + /* keep state under NO PS state, do nothing */ + } + } +} + +static void btc8821a2ant_power_save_state(struct btc_coexist *btcoexist, + u8 ps_type, u8 lps_val, u8 rpwm_val) +{ + bool low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + btc8821a2ant_ps_tdma_check_for_power_save_state(btcoexist, + true); + btc8821a2ant_lps_rpwm(btcoexist, NORMAL_EXEC, lps_val, + rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + btc8821a2ant_ps_tdma_check_for_power_save_state(btcoexist, + false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + static void btc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) { /* fw all off */ + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); @@ -1166,6 +1259,7 @@ static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) btc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); btc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); @@ -1300,6 +1394,8 @@ static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Wifi IPS + BT Busy!!\n"); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); @@ -1658,17 +1754,10 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) 0x5aea5aea, 0xffff, 0x3); } - if (wifi_bw == BTC_WIFI_BW_HT40) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 9); - } else { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 13); - } + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 24); + if (wifi_bw == BTC_WIFI_BW_HT40) { /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { @@ -1683,16 +1772,6 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 9); - } else { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 13); - } - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index ee5aa188af554..804b5b95cab09 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -118,6 +118,10 @@ struct coex_dm_8821a_2ant { u8 cur_algorithm; u8 bt_status; u8 wifi_chnl_info[3]; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; }; struct coex_sta_8821a_2ant { @@ -151,6 +155,7 @@ struct coex_sta_8821a_2ant { u32 crc_err_11g; u32 crc_err_11n; u32 crc_err_11n_agg; + bool force_lps_on; }; /*=========================================== From d09199eb20382a2dd5e61afecd647784cc9697eb Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:00 -0500 Subject: [PATCH 173/201] rtlwifi: btcoex: 21a 2ant: do not check wifi bandwidth Remove workaround for HT40 issues for RF low pass filter. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 36e722a33f0f2..77916ae3d0435 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -958,16 +958,6 @@ static void btc8821a2ant_sw_mechanism1(struct btc_coexist *btcoexist, bool shrink_rx_lpf, bool low_penalty_ra, bool limited_dig, bool bt_lna_constrain) { - u32 wifi_bw; - - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - - if (BTC_WIFI_BW_HT40 != wifi_bw) { - /*only shrink RF Rx LPF for HT40*/ - if (shrink_rx_lpf) - shrink_rx_lpf = false; - } - btc8821a2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); } From d4acd81ed268fed257e8a8b4a40511bebc817244 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:01 -0500 Subject: [PATCH 174/201] rtlwifi: btcoex: 21a 2ant: centralized control of coex table Gather multiple coex table settings into a function coex_table_with_type() and control the coex table according the type value as put in switch-case expression. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 116 +++++++++++++++--- .../rtlwifi/btcoexist/halbtc8821a2ant.h | 2 + 2 files changed, 99 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 77916ae3d0435..4d69955fbebc6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -856,6 +856,89 @@ static void btc8821a2ant_coex_table(struct btc_coexist *btcoexist, coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; } +static void btc8821a2ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffffff, 0x3); + break; + case 1: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5afa5afa, 0xffffff, 0x3); + break; + case 2: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x5ada5ada, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 3: + btc8821a2ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + btc8821a2ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, 0xffffff, 0x3); + break; + case 5: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 8: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 16: + btc8821a2ant_coex_table(btcoexist, force_exec, 0x5fdf5fdf, + 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 17: + btc8821a2ant_coex_table(btcoexist, force_exec, 0xfafafafa, + 0xfafafafa, 0xffffff, 0x3); + break; + default: + break; + } +} + static void btc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex, bool enable) { @@ -1234,8 +1317,7 @@ static void btc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); /* hw all off */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, - 0x55555555, 0x55555555, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); } static void btc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist) @@ -1246,8 +1328,7 @@ static void btc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist) static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) { /* force to reset coex mechanism */ - btc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555, - 0x55555555, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); @@ -1736,12 +1817,10 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) if (wifi_bw == BTC_WIFI_BW_LEGACY) { /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5a5a5a5a, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); } else { /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5aea5aea, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); @@ -1933,9 +2012,9 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, 0x5aff5aff, 0xffff, 0x3); } else { - /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5aff5aff, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); } if (BTC_WIFI_BW_HT40 == wifi_bw) { @@ -2317,13 +2396,13 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (wifi_bw == BTC_WIFI_BW_LEGACY) { - /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5f5b5f5b, 0xffffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); } else { - /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5f5b5f5b, 0xffffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); } if (BTC_WIFI_BW_HT40 == wifi_bw) { @@ -2496,8 +2575,7 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) btc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, false); /* PTA parameter */ - btc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555, 0x55555555, - 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); /* Enable counter statistics */ /*0x76e[3] = 1, WLAN_Act control by PTA*/ diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 804b5b95cab09..6db96cf440342 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -155,6 +155,8 @@ struct coex_sta_8821a_2ant { u32 crc_err_11g; u32 crc_err_11n; u32 crc_err_11n_agg; + + u8 coex_table_type; bool force_lps_on; }; From 3fd7ba4c764c0b6b13e6d764d7761ea3cec12745 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:02 -0500 Subject: [PATCH 175/201] rtlwifi: btcoex: 21a 2ant: check if wifi status changed Monitor wifi status and check if it is changed. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 41 +++++++++++++++++++ .../rtlwifi/btcoexist/halbtc8821a2ant.h | 5 +++ 2 files changed, 46 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 4d69955fbebc6..4030b6429c1d6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -359,6 +359,47 @@ static void btc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } +bool btc8821a2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy = true; + static bool pre_under_4way = true; + static bool pre_bt_hs_on = true; + bool wifi_busy = false, under_4way = false, bt_hs_on = false; + bool wifi_connected = false; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 3, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_LOW)) + return true; + } + + return false; +} + static void btc8821a2ant_update_bt_link_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 6db96cf440342..603e446b59539 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -38,6 +38,11 @@ #define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2 +/* WiFi RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES 42 +/* BT RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES 46 + enum _BT_INFO_SRC_8821A_2ANT { BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0, BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1, From 9153c11cefa3905a3299d2d7b83d9330cf90f5d2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:03 -0500 Subject: [PATCH 176/201] rtlwifi: btcoex: 21a 2ant: ignore wifi if it is at 5G band When wifi is at 5G band, it does not intefere with 2.4G bt signal, hence we can just ignore it and transmit normally as nothing happened. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 4030b6429c1d6..bb609f078a013 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1364,6 +1364,7 @@ static void btc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) static void btc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist) { btc8821a2ant_coex_all_off(btcoexist); + btc8821a2ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); } static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) From aae1e8f5a0f05e0965b56a3cf6bfd2686577e817 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:04 -0500 Subject: [PATCH 177/201] rtlwifi: btcoex: 21a 2ant: set coex table and tdma when bt inquiry Instead of just setting the coex table directly, we check if the wifi is under some important activity (scanning|roaming|linking) and mark the packets as high priority in that case. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index bb609f078a013..7b2fb62947da2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1381,16 +1381,54 @@ static void btc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } -static void btc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist) +static void btc8821a2ant_action_bt_inquiry(struct btc_coexist *btcoexist) { + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + bool wifi_connected = false; bool low_pwr_disable = true; + bool scan = false, link = false, roam = false; + + wifi_rssi_state = + btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5afa5afa, 0xffff, 0x3); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if (scan || link || roam) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi link process + BT Inq/Page!!\n"); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + } else if (wifi_connected) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi no-link + BT Inq/Page!!\n"); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + + btc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) @@ -1779,8 +1817,7 @@ static void btc8821a2ant_action_sco(struct btc_coexist *btcoexist) if (wifi_bw == BTC_WIFI_BW_LEGACY) { /* for SCO quality at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, - 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } else { /* for SCO quality & wifi performance balance at 11n mode */ btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, @@ -2511,7 +2548,7 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], BT is under inquiry/page scan !!\n"); - btc8821a2ant_bt_inquiry_page(btcoexist); + btc8821a2ant_action_bt_inquiry(btcoexist); return; } From 8c670a1b1daeb5c7d2628e0d74fc3594af443a36 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:05 -0500 Subject: [PATCH 178/201] rtlwifi: btcoex: 21a 2ant: let PTA circuit control the switch Register 0xcb4 determines if the PTA circuit can control the swtich Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 7b2fb62947da2..6faa53ee821d2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1109,7 +1109,6 @@ static void btc8821a2ant_set_ant_path(struct btc_coexist *btcoexist, btcoexist->btc_write_4byte(btcoexist, 0x4c, u4tmp); btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff); - btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { /* tell firmware "antenna inverse" ==> WRONG firmware From 8189d81890c150a6268a4660d24cabd603a3a540 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:06 -0500 Subject: [PATCH 179/201] rtlwifi: btcoex: 21a 2ant: slot time fine tune Tune the wifi/bt slot time to get better performance. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 6faa53ee821d2..5991a2cd8678c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1168,12 +1168,12 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, switch (type) { case 1: default: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, - 0x1a, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0xf1, 0x90); break; case 2: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, - 0x12, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x2d, + 0x03, 0xf1, 0x90); break; case 3: btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, @@ -1184,12 +1184,12 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, 0x03, 0xf1, 0x90); break; case 5: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, - 0x1a, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x3, 0x70, 0x90); break; case 6: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, - 0x12, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x2d, + 0x3, 0x70, 0x90); break; case 7: btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, @@ -1200,44 +1200,44 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, 0x3, 0x70, 0x90); break; case 9: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, - 0x1a, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0xf1, 0x90); break; case 10: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x12, - 0x12, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x2d, + 0x03, 0xf1, 0x90); break; case 11: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, - 0xa, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); break; case 12: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, - 0x5, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10, + 0x3, 0xf1, 0x90); break; case 13: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, - 0x1a, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x3, 0x70, 0x90); break; case 14: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, - 0x12, 0x12, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x2d, + 0x3, 0x70, 0x90); break; case 15: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, - 0xa, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); break; case 16: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, - 0x5, 0x60, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x10, + 0x3, 0x70, 0x90); break; case 17: btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x90); break; case 18: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, - 0x5, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x5, 0x5, + 0xe1, 0x90); break; case 19: btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, From 4b764919268783ac0b31bcd16699704310f76b5a Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:07 -0500 Subject: [PATCH 180/201] rtlwifi: btcoex: 21a 2ant: tdma cases for low wifi/bt rssi If the wifi or bt has low rssi, they need extra parameter settings for the tdma. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 5991a2cd8678c..c0537d0268e6e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1145,6 +1145,20 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, { struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 wifi_rssi_state, bt_rssi_state; + + wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + if (!(BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) && + turn_on) { + /* for WiFi RSSI low or BT RSSI low */ + type = type + 100; + } + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], %s turn %s PS TDMA, type = %d\n", (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"), @@ -1251,9 +1265,82 @@ static void btc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); break; + case 23: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1e, + 0x03, 0xf0, 0x14); + break; + case 24: + case 124: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x3c, + 0x03, 0x70, 0x50); + break; + case 25: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x14, + 0x03, 0xf1, 0x90); + break; + case 26: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x30, + 0x03, 0xf1, 0x90); + break; case 71: - btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x1a, - 0x1a, 0xe1, 0x90); + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0xf1, 0x90); + break; + case 101: + case 105: + case 171: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x3a, + 0x03, 0x70, 0x50); + break; + case 102: + case 106: + case 110: + case 114: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x2d, + 0x03, 0x70, 0x50); + break; + case 103: + case 107: + case 111: + case 115: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1c, + 0x03, 0x70, 0x50); + break; + case 104: + case 108: + case 112: + case 116: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x10, + 0x03, 0x70, 0x50); + break; + case 109: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0xf1, 0x90); + break; + case 113: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x3c, + 0x03, 0x70, 0x90); + break; + case 121: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 22: + case 122: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x35, + 0x03, 0x71, 0x11); + break; + case 123: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1c, + 0x03, 0x70, 0x54); + break; + case 125: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x14, + 0x03, 0x70, 0x50); + break; + case 126: + btc8821a2ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x30, + 0x03, 0x70, 0x50); break; } } else { From 3506bc286abe0f3ba2344c8df8a4f688eef6221f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:08 -0500 Subject: [PATCH 181/201] rtlwifi: btcoex: 21a 2ant: action for wifi is idle/linking/common Depending on the state of wifi, we need to set different tdma and coex table parameters to make wfi and bt coexist smoothly. Otherwise the bt may have low sound quality or mouse lag, which mean bad user experience. The same problem may occur on wifi also, if could disconnect or lose some important packets. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 240 +++++++++++------- 1 file changed, 145 insertions(+), 95 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index c0537d0268e6e..f640f6079f9ae 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1517,151 +1517,201 @@ static void btc8821a2ant_action_bt_inquiry(struct btc_coexist *btcoexist) btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } -static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) +void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; - bool common = false, wifi_connected = false, wifi_busy = false; - bool low_pwr_disable = false; + u8 u8tmpa, u8tmpb; - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, - &wifi_connected); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5afa5afa, 0xffff, 0x3); + btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); - if (!wifi_connected && - BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) { - low_pwr_disable = false; - btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, - &low_pwr_disable); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi IPS + BT IPS!!\n"); + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], 0x765=0x%x, 0x76e=0x%x\n", u8tmpa, u8tmpb); +} - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); +static bool btc8821a2ant_action_wifi_idle_process(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; - btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, - false); - btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, - 0x18); + wifi_rssi_state = + btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES - 20, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); - common = true; - } else if (wifi_connected && - (BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)) { - low_pwr_disable = false; - btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, - &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); - if (wifi_busy) { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi Busy + BT IPS!!\n"); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 1); - } else { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi LPS + BT IPS!!\n"); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 1); - } + /* define the office environment */ + if (BTC_RSSI_HIGH(wifi_rssi_state1) && (coex_sta->hid_exist) && + (coex_sta->a2dp_exist)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi idle process for BT HID+A2DP exist!!\n"); - btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + /* sw all off */ btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); - common = true; - } else if (!wifi_connected && - (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) { - low_pwr_disable = true; - btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, - &low_pwr_disable); - btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, - 0x8); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + return true; + } else if (coex_sta->pan_exist) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi IPS + BT LPS!!\n"); + "[BTCoex], Wifi idle process for BT PAN exist!!\n"); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + /* sw all off */ btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); - common = true; - } else if (wifi_connected && - (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) { - low_pwr_disable = true; - btcoexist->btc_set(btcoexist, - BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); - if (wifi_busy) { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi Busy + BT LPS!!\n"); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 1); - } else { - RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi LPS + BT LPS!!\n"); - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 1); - } + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + return true; + } + btc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x18); + return false; +} - btc8821a2ant_sw_mechanism1(btcoexist, true, true, true, true); - btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, - 0x18); +static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + bool common = false, wifi_connected = false, wifi_busy = false; + bool low_pwr_disable = false; + bool bt_hs_on = false; - common = true; - } else if (!wifi_connected && - (coex_dm->bt_status == BT_8821A_2ANT_BT_STATUS_NON_IDLE)) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected) { low_pwr_disable = false; btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi IPS + BT Busy!!\n"); + "[BTCoex], Wifi non-connected idle!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); - btc8821a2ant_sw_mechanism1(btcoexist, false, false, - false, false); - btc8821a2ant_sw_mechanism2(btcoexist, false, false, - false, 0x18); + btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, + false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); common = true; } else { - low_pwr_disable = true; - btcoexist->btc_set(btcoexist, - BTC_SET_ACT_DISABLE_LOW_POWER, - &low_pwr_disable); + if (BT_8821A_2ANT_BT_STATUS_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); - if (wifi_busy) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi Busy + BT Busy!!\n"); - common = false; - } else { + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + btc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + btc8821a2ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8821A_2ANT_BT_STATUS_CON_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hs_on) + return false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], Wifi LPS + BT Busy!!\n"); - btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, true, 21); + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + btc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + btc8821a2ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + btc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); common = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + common = false; + } else { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + common = + btc8821a2ant_action_wifi_idle_process( + btcoexist); + } } - btc8821a2ant_sw_mechanism1(btcoexist, true, true, true, true); } return common; } From 20ec48e51d252daa5c829061b7af596faf75209b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:09 -0500 Subject: [PATCH 182/201] rtlwifi: btcoex: 21a 2ant: fix invalid argument passed The dac swing level should be an unsigned 32-bit value rather than boolean. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index f640f6079f9ae..3bdf691c9d08c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1090,7 +1090,7 @@ static void btc8821a2ant_sw_mechanism2(struct btc_coexist *btcoexist, bool sw_dac_swing, u32 dac_swing_lvl) { btc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, - sw_dac_swing); + dac_swing_lvl); } static void btc8821a2ant_set_ant_path(struct btc_coexist *btcoexist, From 3f775d5cee7966e41354a45377e34b9c01cf1f79 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 13 Apr 2017 13:07:10 -0500 Subject: [PATCH 183/201] rtlwifi: btcoex: 21a 2ant: refine tdma duration adjust function 1. Add more cases to adjust the wifi duration and add a case with the max interval of 3 for some future uses. 2. rename tdma_adj -> ps_tdma_du_adj to indicate that this member is for power saving tdma duration adjustment Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 968 ++++++++++++++++-- .../rtlwifi/btcoexist/halbtc8821a2ant.h | 3 +- 2 files changed, 893 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 3bdf691c9d08c..0ef83727fdf44 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1716,9 +1716,9 @@ static bool btc8821a2ant_is_common_action(struct btc_coexist *btcoexist) return common; } -static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist, - bool sco_hid, bool tx_pause, - u8 max_interval) +static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) { struct rtl_priv *rtlpriv = btcoexist->adapter; static long up, dn, m, n, wait_count; @@ -1732,80 +1732,84 @@ static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], TdmaDurationAdjust()\n"); - if (coex_dm->reset_tdma_adjust) { - coex_dm->reset_tdma_adjust = false; + if (coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], first run TdmaDurationAdjust()!!\n"); if (sco_hid) { if (tx_pause) { if (max_interval == 1) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 13); - coex_dm->tdma_adj_type = 13; + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; } else if (max_interval == 2) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 14); - coex_dm->tdma_adj_type = 14; + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (max_interval == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; } else { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 15); - coex_dm->tdma_adj_type = 15; + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; } } else { if (max_interval == 1) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 9); - coex_dm->tdma_adj_type = 9; + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; } else if (max_interval == 2) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 10); - coex_dm->tdma_adj_type = 10; + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (max_interval == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; } else { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 11); - coex_dm->tdma_adj_type = 11; + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; } } } else { if (tx_pause) { if (max_interval == 1) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 5); - coex_dm->tdma_adj_type = 5; + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; } else if (max_interval == 2) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 6); - coex_dm->tdma_adj_type = 6; + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (max_interval == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; } else { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 7); - coex_dm->tdma_adj_type = 7; + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; } } else { if (max_interval == 1) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 1); - coex_dm->tdma_adj_type = 1; + NORMAL_EXEC, true, 1); + coex_dm->ps_tdma_du_adj_type = 1; } else if (max_interval == 2) { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 2); - coex_dm->tdma_adj_type = 2; + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (max_interval == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; } else { btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, - true, 3); - coex_dm->tdma_adj_type = 3; + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; } } } @@ -1902,18 +1906,716 @@ static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], max Interval = %d\n", max_interval); + + if (max_interval == 1) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 71) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + btc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } } /* if current PsTdma not match with the recorded one * (when scan, dhcp...), then we have to adjust it back to * the previous recorded one. */ - if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) { - bool scan = false, link = false, roam = false; + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + bool scan = false, link = false, roam = false; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n", - coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); @@ -1921,14 +2623,12 @@ static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist, if (!scan && !link && !roam) { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, - coex_dm->tdma_adj_type); + coex_dm->ps_tdma_du_adj_type); } else { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); } } - - btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); } /* SCO only or SCO+PAN(HS)*/ @@ -2082,7 +2782,7 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); - /* fw dac swing is called in btc8821a2ant_tdma_dur_adj() + /* fw dac swing is called in btc8821a2ant_tdma_duration_adjust() * btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); */ @@ -2097,9 +2797,11 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) /* fw mechanism */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + false, 1); } else { - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 1); } /* sw mechanism */ @@ -2119,9 +2821,11 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) /* fw mechanism */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + false, 1); } else { - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 1); } /* sw mechanism */ @@ -2160,10 +2864,12 @@ static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) /* fw mechanism */ if (bt_info_ext&BIT0) { /* a2dp basic rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 2); } else { /* a2dp edr rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 1); } /* sw mechanism */ @@ -2183,10 +2889,12 @@ static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) /* fw mechanism */ if (bt_info_ext&BIT0) { /* a2dp basic rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 2); } else { /* a2dp edr rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 1); } /* sw mechanism */ @@ -2384,12 +3092,27 @@ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) if (BTC_WIFI_BW_HT40 == wifi_bw) { /* fw mechanism */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) - btc8821a2ant_tdma_dur_adj(btcoexist, false, - false, 3); - else - btc8821a2ant_tdma_dur_adj(btcoexist, false, - true, 3); + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, false, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, false, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, true, 3); + } + } /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -2407,10 +3130,27 @@ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) } else { /* fw mechanism */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) - btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 3); - else - btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 3); + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, false, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, false, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + false, true, 3); + } + } /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -2538,7 +3278,28 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) if (BTC_WIFI_BW_HT40 == wifi_bw) { /* fw mechanism */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, true, 3); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, 3); + } + } /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -2559,22 +3320,24 @@ static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { if (bt_info_ext&BIT0) { /* a2dp basic rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, - false, 3); + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, false, 3); } else { /* a2dp edr rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, - false, 3); + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, false, 3); } } else { if (bt_info_ext&BIT0) { /* a2dp basic rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, - true, 3); + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 3); } else { /* a2dp edr rate */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, - true, 3); + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 3); } } @@ -2622,7 +3385,32 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) if (BTC_WIFI_BW_HT40 == wifi_bw) { /* fw mechanism */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, true, 2); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (bt_info_ext & BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } + } else { + if (bt_info_ext & BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } + } /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || @@ -2639,7 +3427,33 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) } } else { /* fw mechanism */ - btc8821a2ant_tdma_dur_adj(btcoexist, true, true, 2); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (bt_info_ext & BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } + } else { + if (bt_info_ext & BIT0) { + /*a2dp basic rate*/ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } else { + /*a2dp edr rate*/ + btc8821a2ant_tdma_duration_adjust(btcoexist, + true, true, + 2); + } + } /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h index 603e446b59539..535ca10e910b3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -87,8 +87,9 @@ struct coex_dm_8821a_2ant { u8 pre_ps_tdma; u8 cur_ps_tdma; u8 ps_tdma_para[5]; - u8 tdma_adj_type; + u8 ps_tdma_du_adj_type; bool reset_tdma_adjust; + bool auto_tdma_adjust; bool pre_ps_tdma_on; bool cur_ps_tdma_on; bool pre_bt_auto_report; From 1a2534930e9ec51fe459dc5dd592e496ecd99750 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:47 -0500 Subject: [PATCH 184/201] rtlwifi: btcoex: 21a 2ant: turn on sw dac swing and check if is sco_only Use software dac swing and double check if it is sco_only to set the tdma for voice quality. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 0ef83727fdf44..7b5dbc62906ec 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2634,13 +2634,15 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, /* SCO only or SCO+PAN(HS)*/ static void btc8821a2ant_action_sco(struct btc_coexist *btcoexist) { + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; u8 wifi_rssi_state, bt_rssi_state; u32 wifi_bw; - wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, - 15, 0); + wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); @@ -2656,58 +2658,49 @@ static void btc8821a2ant_action_sco(struct btc_coexist *btcoexist) btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); } else { /* for SCO quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, - 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); - } - - if (wifi_bw == BTC_WIFI_BW_HT40) { - - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - /* for voice quality */ - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 0); + if (wifi_bw == BTC_WIFI_BW_HT40) { + btc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); } else { - /* for voice quality */ - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - false, 0); + if (bt_link_info->sco_only) + btc8821a2ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 17); + else + btc8821a2ant_coex_table_with_type( + btcoexist, NORMAL_EXEC, 12); } + } - /* sw mechanism */ + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + /* for voice quality */ + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, true, false, false); btc8821a2ant_sw_mechanism2(btcoexist, true, false, - false, 0x18); + true, 0x18); } else { btc8821a2ant_sw_mechanism1(btcoexist, true, true, false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, - false, 0x18); + true, 0x18); } } else { - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - /* for voice quality */ - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); - } else { - /* for voice quality */ - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, true, false, false); btc8821a2ant_sw_mechanism2(btcoexist, true, false, - false, 0x18); + true, 0x18); } else { btc8821a2ant_sw_mechanism1(btcoexist, false, true, false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, - false, 0x18); + true, 0x18); } } } From 124e50ff6582a45668c18984e6371f3ca5a30ba7 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:48 -0500 Subject: [PATCH 185/201] rtlwifi: btcoex: 21a 2ant: add threshold to examine bt rssi The threshold is used to adjust the base line for the rssi state. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 7b5dbc62906ec..b880bc2eaf85a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2711,7 +2711,8 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) u32 wifi_bw; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); From 10c2e1cc15e4e2202413eae601dd229682cb9bea Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:49 -0500 Subject: [PATCH 186/201] rtlwifi: btcoex: 21a 2ant: force wifi to use RF path A Let the wifi use main antenna to have higher power. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index b880bc2eaf85a..8437f1b6c1083 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2714,6 +2714,8 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); From 70a8adef7108f3b8773c35b80fbd46d9d7df92b3 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:50 -0500 Subject: [PATCH 187/201] rtlwifi: btcoex: 21a 2ant: more combinations of wifi/bt rssi state For bt a2dp, we need to check more rssi state combinations to have better voice quality. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 97 +++++++++++++------ 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 8437f1b6c1083..62c3556e83b50 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2771,36 +2771,80 @@ static void btc8821a2ant_action_hid(struct btc_coexist *btcoexist) /* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; u32 wifi_bw; - wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, - 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); - /* fw dac swing is called in btc8821a2ant_tdma_duration_adjust() - * btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - */ + if ((ap_num >= 10) && BTC_RSSI_HIGH(wifi_rssi_state1) && + BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); - if (BTC_RSSI_HIGH(bt_rssi_state)) - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); - else - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - false, 1); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) { + btc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); } else { - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 1); + btc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); } + return; + } - /* sw mechanism */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } else { + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, false, @@ -2814,17 +2858,6 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - false, 1); - } else { - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 1); - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, false, From f0557cf062c7d7f220aa89fbdc037d208e4ad11b Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:51 -0500 Subject: [PATCH 188/201] rtlwifi: btcoex: 21a 2ant: fix some coding style issues Fix some ident and naming for linux coding style. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 62c3556e83b50..bbce0cbe2e9ab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3512,8 +3512,7 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } - btcoexist->btc_get(btcoexist, - BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); if (wifi_under_5g) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -3629,15 +3628,15 @@ void ex_btc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) u1tmp |= 0x5; btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp); - /*Antenna config */ + /* Antenna config */ btc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, false); /* PTA parameter */ btc8821a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); /* Enable counter statistics */ - /*0x76e[3] = 1, WLAN_Act control by PTA*/ - btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + /* 0x76e[3] = 1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } From 137cc90f094a53496a8b497e54e2d699291eaa7a Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:52 -0500 Subject: [PATCH 189/201] rtlwifi: btcoex: 21a 2ant: set tdma based on rssi state amd limit rx agg size Monitor the rssi state to set the tdma and limit rx aggregation size to fit the bt profiling. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index bbce0cbe2e9ab..9df5b4c195fff 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2875,33 +2875,40 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); else btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } - if (wifi_bw == BTC_WIFI_BW_HT40) { - /* fw mechanism */ - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 1); - } + btc8821a2ant_tdma_duration_adjust(btcoexist, false, true, 2); - /* sw mechanism */ + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, false, @@ -2915,18 +2922,6 @@ static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 2); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, false, - true, 1); - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, false, From 0fcad45bdbf7b013dabc3a09026ad47f01ea5fd2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:53 -0500 Subject: [PATCH 190/201] rtlwifi: btcoex: 21a 2ant: add multiport action for p2p/miracast For p2p/miracast, the wifi may have multiple ports for different roles. Under this, we need extra settings for turning off the tdma and proper coex table parameters. We monnitor the number of links on a port to determine if it is for p2p/miracast or not. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 9df5b4c195fff..4471bd66a2e51 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3495,11 +3495,31 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) } } +static void btc8821a2ant_action_wifi_multi_port(struct btc_coexist *btcoexist) +{ + btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + btc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +} + static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; bool wifi_under_5g = false; u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + bool miracast_plus_bt = false; if (btcoexist->manual_control) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -3525,6 +3545,33 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + btc8821a2ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + coex_dm->cur_algorithm = algorithm; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); From a4162ea71b39667e0393480080819be095fc7a33 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:54 -0500 Subject: [PATCH 191/201] rtlwifi: btcoex: 21a 2ant: monitor extra wifi rssi to examine network status Here we monitor one more wifi rssi to check the status of the network and set the coex table instead of the legacy way. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 4471bd66a2e51..b93a4f7ce17a8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -2939,11 +2939,18 @@ static void btc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); @@ -2952,30 +2959,25 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) else btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - - if (BTC_WIFI_BW_LEGACY == wifi_bw) { - /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5aff5aff, 0xffff, 0x3); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 10); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); } else { btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, 0x4); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 1); - } else { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 5); - } + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26); + else + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26); - /* sw mechanism */ + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, false, @@ -2989,17 +2991,6 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 1); - } else { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, 5); - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, false, From f76184d024571c9f39d66a38bedfab33e6322039 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:55 -0500 Subject: [PATCH 192/201] rtlwifi: btcoex: 21a 2ant: notify fw the number of APs Use h2c to tell the firmware if the number of AP is more than 10 or not. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index b93a4f7ce17a8..9e152117730ce 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3982,6 +3982,7 @@ void ex_btc8821a2ant_media_status_notify(struct btc_coexist *btcoexist, u8 h2c_parameter[3] = {0}; u32 wifi_bw; u8 wifi_central_chnl; + u8 ap_num = 0; if (BTC_MEDIA_CONNECT == type) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -3999,10 +4000,15 @@ void ex_btc8821a2ant_media_status_notify(struct btc_coexist *btcoexist, h2c_parameter[0] = 0x1; h2c_parameter[1] = wifi_central_chnl; btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - if (BTC_WIFI_BW_HT40 == wifi_bw) + if (wifi_bw == BTC_WIFI_BW_HT40) { h2c_parameter[2] = 0x30; - else + } else { h2c_parameter[2] = 0x20; + if (ap_num < 10) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } } coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; From c129bc843b629623580c248e9f7f91c1f503dc9d Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:56 -0500 Subject: [PATCH 193/201] rtlwifi: btcoex: 21a 2ant: dec bt power according to bt rssi and set tdma Check the bt rssi first and decrease it if the bt rssi is too high. Then set the tdma and coex table. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../rtlwifi/btcoexist/halbtc8821a2ant.c | 140 ++++++------------ 1 file changed, 48 insertions(+), 92 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 9e152117730ce..626b73fd97a5d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3009,28 +3009,31 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) /* PAN(HS) only */ static void btc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; u32 wifi_bw; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_RSSI_HIGH(bt_rssi_state)) + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); - } else { - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); - } - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, false, @@ -3044,22 +3047,6 @@ static void btc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) false, 0x18); } } else { - /* fw mechanism */ - if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || - (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); - } else { - btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); - } - - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - } else { - btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); - } - - /* sw mechanism */ if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, false, @@ -3078,12 +3065,18 @@ static void btc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) /* PAN(EDR)+A2DP */ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) { - u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; - u32 wifi_bw; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; - bt_info_ext = coex_sta->bt_info_ext; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + wifi_rssi_state1 = btc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); @@ -3092,44 +3085,32 @@ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) else btc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) + btc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + btc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); - if (wifi_bw == BTC_WIFI_BW_LEGACY) { - /* for HID at 11b/g mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5afa5afa, 0xffff, 0x3); + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 12); + + if (wifi_bw == BTC_WIFI_BW_HT40) + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 3); + else + btc8821a2ant_tdma_duration_adjust(btcoexist, false, + false, 3); } else { - /* for HID quality & wifi performance balance at 11n mode */ - btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, - 0x5afa5afa, 0xffff, 0x3); + btc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 13); + btc8821a2ant_tdma_duration_adjust(btcoexist, false, true, 3); } - if (BTC_WIFI_BW_HT40 == wifi_bw) { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, false, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, false, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, true, 3); - } - } - - /* sw mechanism */ + /* sw mechanism */ + if (wifi_bw == BTC_WIFI_BW_HT40) { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, true, false, @@ -3141,33 +3122,8 @@ static void btc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) false, false); btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); - }; - } else { - /* fw mechanism */ - if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || - (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, false, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, false, 3); - } - } else { - if (bt_info_ext&BIT0) { - /* a2dp basic rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, true, 3); - } else { - /* a2dp edr rate */ - btc8821a2ant_tdma_duration_adjust(btcoexist, - false, true, 3); - } } - - /* sw mechanism */ + } else { if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_sw_mechanism1(btcoexist, false, false, From 97632f8c0a934b5f01383db0cc8a1c2ac6cf4e2c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:57 -0500 Subject: [PATCH 194/201] rtlwifi: btcoex: 21a 2ant: macro for bt rssi threshold Using macro to control the bt threshold. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 626b73fd97a5d..5a8e4b80006bc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3145,7 +3145,8 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) u32 wifi_bw; wifi_rssi_state = btc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, 35, 0); + bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, + 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); From 63a7e8109b2cd0bd73dac3ee503430e3030eee10 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:58 -0500 Subject: [PATCH 195/201] rtlwifi: btcoex: 21a 2ant: do not limit rx agg size For bt profiling, we do not need to limit the rx agg size. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 5a8e4b80006bc..22cb8aa8208d8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3148,7 +3148,6 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) bt_rssi_state = btc8821a2ant_bt_rssi_state(btcoexist, 2, BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); - btc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); btc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); if (BTC_RSSI_HIGH(bt_rssi_state)) From 67cbe62a27dcc100484fde60c9ac1d89eaac911f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:31:59 -0500 Subject: [PATCH 196/201] rtlwifi: btcoex: 21a 2ant: just return when wifi is under ips If wifi is in power saving mode, do nothing. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 6 ++++++ 1 file changed, 6 insertions(+) Signed-off-by: Kalle Valo --- .../wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 22cb8aa8208d8..0aa36247e4023 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3483,6 +3483,12 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } + if (coex_sta->under_ips) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + algorithm = btc8821a2ant_action_algorithm(btcoexist); if (coex_sta->c2h_bt_inquiry_page && (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) { From f9558f5fc86b614f905e4f86aed750b433056688 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Sat, 15 Apr 2017 15:32:00 -0500 Subject: [PATCH 197/201] rtlwifi: btcoex: 21a 2ant: wifi is linking action When wifi is under scanning/linking/roaming, do not run the reset of the coex mechanism because these activities are important for wifi, just run the linking process and return. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Larry Finger Cc: Pkshih Cc: Birming Chiu Cc: Shaofu Signed-off-by: Kalle Valo --- .../realtek/rtlwifi/btcoexist/halbtc8821a2ant.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 0aa36247e4023..841b4a83ab70c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3467,6 +3467,7 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) u32 num_of_wifi_link = 0; u32 wifi_link_status = 0; bool miracast_plus_bt = false; + bool scan = false, link = false, roam = false; if (btcoexist->manual_control) { RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -3498,6 +3499,17 @@ static void btc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) return; } + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, + "[BTCoex], WiFi is under Link Process !!\n"); + btc8821a2ant_action_wifi_link_process(btcoexist); + return; + } + /* for P2P */ btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); From 225a644aae03ffe2ec186cd994cd5ab241130035 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 17 Apr 2017 21:30:12 +0200 Subject: [PATCH 198/201] rt2800: fix LNA gain assignment for MT7620 The base value used for MT7620 differs from Rt5392 which resulted in quite bad RX signal quality. Fix this by using the correct base value as well as the LNA calibration values for HT20. Reported-by: Tom Psyborg Signed-off-by: Daniel Golle Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index ba06ac2d876da..7135519a638c9 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -3806,11 +3806,25 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } if (rt2x00_rt(rt2x00dev, RT5592) || rt2x00_rt(rt2x00dev, RT6352)) { + reg = 0x10; + if (!conf_is_ht40(conf)) { + if (rt2x00_rt(rt2x00dev, RT6352) && + rt2x00_has_cap_external_lna_bg(rt2x00dev)) { + reg |= 0x5; + } else { + reg |= 0xa; + } + } rt2800_bbp_write(rt2x00dev, 195, 141); - rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a); + rt2800_bbp_write(rt2x00dev, 196, reg); /* AGC init */ - reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2 * rt2x00dev->lna_gain; + if (rt2x00_rt(rt2x00dev, RT6352)) + reg = 0x04; + else + reg = rf->channel <= 14 ? 0x1c : 0x24; + + reg += 2 * rt2x00dev->lna_gain; rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg); rt2800_iq_calibrate(rt2x00dev, rf->channel); From 2031badabf269067f9bc581fea946a27229e4030 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 17 Apr 2017 21:32:12 +0200 Subject: [PATCH 199/201] rt2800: do VCO calibration after programming ALC Somehow AP doesn't come up and the first scan fails if we don't do VCO calibration every time. The vendor driver duplicates the VCO calibration function into the channel switching logic, we can do the same with less duplication. Signed-off-by: Daniel Golle Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 7135519a638c9..870bf315f98be 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -3407,6 +3407,8 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); } rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl); + + rt2800_vco_calibration(rt2x00dev); } static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev, From 4bd96b5d3379b00164f454084bbe0ea7d9f752a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomislav=20Po=C5=BEega?= Date: Tue, 18 Apr 2017 11:32:35 +0200 Subject: [PATCH 200/201] rt2800: fix mt7620 vco calibration registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use register values from init LNA function instead of the ones from restore LNA function. Apply register values based on rx path configuration. Signed-off-by: Tomislav Požega Signed-off-by: Daniel Golle Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 870bf315f98be..86cffee6876a7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -4932,7 +4932,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); if (rt2x00_rt(rt2x00dev, RT6352)) { - if (rt2x00dev->default_ant.tx_chain_num == 1) { + if (rt2x00dev->default_ant.rx_chain_num == 1) { rt2800_bbp_write(rt2x00dev, 91, 0x07); rt2800_bbp_write(rt2x00dev, 95, 0x1A); rt2800_bbp_write(rt2x00dev, 195, 128); @@ -4953,8 +4953,8 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) } if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { - rt2800_bbp_write(rt2x00dev, 75, 0x60); - rt2800_bbp_write(rt2x00dev, 76, 0x44); + rt2800_bbp_write(rt2x00dev, 75, 0x68); + rt2800_bbp_write(rt2x00dev, 76, 0x4C); rt2800_bbp_write(rt2x00dev, 79, 0x1C); rt2800_bbp_write(rt2x00dev, 80, 0x0C); rt2800_bbp_write(rt2x00dev, 82, 0xB6); From a0597834dc0e1af68f48f92b31617b360a14dfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomislav=20Po=C5=BEega?= Date: Tue, 18 Apr 2017 11:52:07 +0200 Subject: [PATCH 201/201] rt2800: fix mt7620 E2 channel registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update RF register 47 and 54 values according to vendor driver Signed-off-by: Tomislav Požega Signed-off-by: Daniel Golle Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 86cffee6876a7..8585cdc3de53e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -8145,9 +8145,11 @@ static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); - rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x69); + rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67); + rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69); rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); - rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x20); + rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27); + rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20); rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C);