From 4549cf2b1803d29cfd019f7bfeaa784f8f9c558f Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 2 Sep 2014 14:05:10 +0200 Subject: mac80211: fix offloaded BA session traffic after hw restart When starting an offloaded BA session it is unknown what starting sequence number should be used. Using last_seq worked in most cases except after hw restart. When hw restart is requested last_seq is (rightfully so) kept unmodified. This ended up with BA sessions being restarted with an aribtrary BA window values resulting in dropped frames until sequence numbers caught up. Instead of last_seq pick seqno of a first Rxed frame of a given BA session. This fixes stalled traffic after hw restart with offloaded BA sessions (currently only ath10k). Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index f0e84bc..a48bad4 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -227,7 +227,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d void __ieee80211_start_rx_ba_session(struct sta_info *sta, u8 dialog_token, u16 timeout, u16 start_seq_num, u16 ba_policy, u16 tid, - u16 buf_size, bool tx) + u16 buf_size, bool tx, bool auto_seq) { struct ieee80211_local *local = sta->sdata->local; struct tid_ampdu_rx *tid_agg_rx; @@ -326,6 +326,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, tid_agg_rx->buf_size = buf_size; tid_agg_rx->timeout = timeout; tid_agg_rx->stored_mpdu_num = 0; + tid_agg_rx->auto_seq = auto_seq; status = WLAN_STATUS_SUCCESS; /* activate it for RX */ @@ -367,7 +368,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, start_seq_num, ba_policy, tid, - buf_size, true); + buf_size, true, false); } void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ffb20e5..8fe5433 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1587,7 +1587,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, void __ieee80211_start_rx_ba_session(struct sta_info *sta, u8 dialog_token, u16 timeout, u16 start_seq_num, u16 ba_policy, u16 tid, - u16 buf_size, bool tx); + u16 buf_size, bool tx, bool auto_seq); void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, enum ieee80211_agg_stop_reason reason); void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 01eede7..bb7288e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1172,19 +1172,11 @@ static void ieee80211_iface_work(struct work_struct *work) rx_agg = (void *)&skb->cb; mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, rx_agg->addr); - if (sta) { - u16 last_seq; - - last_seq = le16_to_cpu( - sta->last_seq_ctrl[rx_agg->tid]); - + if (sta) __ieee80211_start_rx_ba_session(sta, - 0, 0, - ieee80211_sn_inc(last_seq), - 1, rx_agg->tid, + 0, 0, 0, 1, rx_agg->tid, IEEE80211_MAX_AMPDU_BUF, - false); - } + false, true); mutex_unlock(&local->sta_mtx); } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) { rx_agg = (void *)&skb->cb; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a8d862f..41eb12c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -835,6 +835,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata spin_lock(&tid_agg_rx->reorder_lock); + /* + * Offloaded BA sessions have no known starting sequence number so pick + * one from first Rxed frame for this tid after BA was started. + */ + if (unlikely(tid_agg_rx->auto_seq)) { + tid_agg_rx->auto_seq = false; + tid_agg_rx->ssn = mpdu_seq_num; + tid_agg_rx->head_seq_num = mpdu_seq_num; + } + buf_size = tid_agg_rx->buf_size; head_seq_num = tid_agg_rx->head_seq_num; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 89c40d5..16dc1d4 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -167,6 +167,8 @@ struct tid_ampdu_tx { * @dialog_token: dialog token for aggregation session * @rcu_head: RCU head used for freeing this struct * @reorder_lock: serializes access to reorder buffer, see below. + * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and + * and ssn. * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -190,6 +192,7 @@ struct tid_ampdu_rx { u16 buf_size; u16 timeout; u8 dialog_token; + bool auto_seq; }; /** -- cgit v0.10.2 From c10a19930f286a24f4994c83fe71866877fb1a71 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 5 Sep 2014 10:56:35 +0200 Subject: mac80211: clean up ieee80211_i.h Not sure how the declaration of ieee80211_tdls_peer_del_work landed after the double inclusion protection end. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8fe5433..78f9538 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1917,7 +1917,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, size_t extra_ies_len); int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); - +void ieee80211_tdls_peer_del_work(struct work_struct *wk); extern const struct ethtool_ops ieee80211_ethtool_ops; @@ -1928,4 +1928,3 @@ extern const struct ethtool_ops ieee80211_ethtool_ops; #endif #endif /* IEEE80211_I_H */ -void ieee80211_tdls_peer_del_work(struct work_struct *wk); -- cgit v0.10.2 From d98ad83ee86e523cc00cbf425f456fbd14b4fdc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Sep 2014 15:24:57 +0300 Subject: mac80211: add Intel Mobile Communications copyright Our legal structure changed at some point (see wikipedia), but we forgot to immediately switch over to the new copyright notice. For files that we have modified in the time since the change, add the proper copyright notice now. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c9b2bec..db4975c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4,6 +4,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4d8989b..d7f437e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2,6 +2,7 @@ * mac80211 configuration hooks for cfg80211 * * Copyright 2006-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This file is GPLv2 as found in COPYING. */ diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 0e963bc..5746561 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -3,6 +3,7 @@ * mac80211 debugfs for wireless PHYs * * Copyright 2007 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * GPLv2 * diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 4a20fb8..b5e0a53 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -2,6 +2,7 @@ * Copyright 2003-2005 Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc * Copyright 2007 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5f9654d..56b5357 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -6,6 +6,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu * Copyright 2009, Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 78f9538..b9d9508 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -3,6 +3,7 @@ * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bb7288e..af23722 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -5,6 +5,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc * Copyright 2008, Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 6429d0e..f320a04 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007-2008 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e0ab432..0de7c93 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -2,6 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29fe91d..305e510 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5,6 +5,7 @@ * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 41eb12c..b04ca40 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a9bb6eb..af0d094 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -6,6 +6,7 @@ * Copyright 2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e1f957d..215752e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1,6 +1,7 @@ /* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2006-2007 Jiri Benc + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 16dc1d4..9dc7a9d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -1,5 +1,6 @@ /* * Copyright 2002-2005, Devicescape Software, Inc. + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/status.c b/net/mac80211/status.c index aa06dca..2800e1c 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2008-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index f2cb3b6..bcf51e4 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -3,6 +3,7 @@ * * Copyright 2006-2010 Johannes Berg * Copyright 2014, Intel Corporation + * Copyright 2014 Intel Mobile Communications GmbH * * This file is GPLv2 as found in COPYING. */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 925c39f..d1b3c22 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 725af7a..b444f27 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 6459946..3b87398 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -1,5 +1,6 @@ /* * Copyright 2004, Instant802 Networks, Inc. + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as -- cgit v0.10.2 From 2740f0cf8ec8bc7ee6a58f68841759e367dda98f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 3 Sep 2014 15:24:58 +0300 Subject: cfg80211: add Intel Mobile Communications copyright Our legal structure changed at some point (see wikipedia), but we forgot to immediately switch over to the new copyright notice. For files that we have modified in the time since the change, add the proper copyright notice now. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 8018c91..77d4f26 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -6,6 +6,7 @@ * Copyright (c) 2002-2003, Jouni Malinen * Copyright (c) 2005, Devicescape Software, Inc. * Copyright (c) 2006, Michael Wu + * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ab21299..6be68bb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4,6 +4,7 @@ * 802.11 device and configuration interface * * Copyright 2006-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 992b340..72d81e2 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -4,6 +4,7 @@ * any point in time. * * Copyright 2009 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH */ #include diff --git a/net/wireless/core.c b/net/wireless/core.c index a207eb1..9698fe70 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -2,6 +2,7 @@ * This is the linux wireless configuration interface. * * Copyright 2006-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3011401..d876146 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2,6 +2,7 @@ * This is the new netlink-based wireless configuration interface. * * Copyright 2006-2010 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH */ #include diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 1afdf45..8bfc9b1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3,6 +3,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2007 Johannes Berg * Copyright 2008-2011 Luis R. Rodriguez + * Copyright 2013-2014 Intel Mobile Communications GmbH * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 620a4b4..bda39f1 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2,6 +2,7 @@ * cfg80211 scan result handling * * Copyright 2008 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH */ #include #include diff --git a/net/wireless/util.c b/net/wireless/util.c index 728f1c0..a8b2816 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -2,6 +2,7 @@ * Wireless utility functions * * Copyright 2007-2009 Johannes Berg + * Copyright 2013-2014 Intel Mobile Communications GmbH */ #include #include -- cgit v0.10.2 From 6188c271f0f2cbc89a52981d252107f7f409f45f Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Wed, 3 Sep 2014 15:24:59 +0300 Subject: mac80211: fix description comment of ieee80211_subif_start_xmit The function description claimed that on error the skb isn't freed even though it is, and stated return values that are different than what really happens in the code. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d1b3c22..2f7754c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1789,9 +1789,8 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, * @skb: packet to be sent * @dev: incoming interface * - * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will - * not be freed, and caller is responsible for either retrying later or freeing - * skb). + * Returns: NETDEV_TX_OK both on success and on failure. On failure skb will + * be freed. * * This function takes in an Ethernet header and encapsulates it with suitable * IEEE 802.11 header based on which interface the packet is coming in. The -- cgit v0.10.2 From 1c7e23bf50264a251de53ad9fb1604683b801258 Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 3 Sep 2014 15:25:00 +0300 Subject: nl80211: Allow declaring RRM-related features Radio Resource Measurement (RRM) is a bundle of features which will require the entire stack to participate. In this patch, the driver is given the opportunity to advertise the device's support for these RRM-related features, using feature flags: 1. Support for Quiet IEs. 2. Support for adding DS Parameter Set IE to probe requests. 3. Support for adding WFA TPC Report IE to probe requests. 4. Support for inserting tx power value to tx-ed packets at a fixed offset. This is used in action frames, such as RRM's Link Measurement Report, where the actual tx power should be reported in the frame. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d097568..c166d3d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3968,6 +3968,16 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic * channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the * lifetime of a BSS. + * @NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES: This device adds a DS Parameter + * Set IE to probe requests. + * @NL80211_FEATURE_WFA_TPC_IE_IN_PROBES: This device adds a WFA TPC Report IE + * to probe requests. + * @NL80211_FEATURE_QUIET: This device, in client mode, supports Quiet Period + * requests sent to it by an AP. + * @NL80211_FEATURE_TX_POWER_INSERTION: This device is capable of inserting the + * current tx power value into the TPC Report IE in the spectrum + * management TPC Report action frame, and in the Radio Measurement Link + * Measurement Report action frame. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -3989,6 +3999,10 @@ enum nl80211_feature_flags { NL80211_FEATURE_USERSPACE_MPM = 1 << 16, NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18, + NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES = 1 << 19, + NL80211_FEATURE_WFA_TPC_IE_IN_PROBES = 1 << 20, + NL80211_FEATURE_QUIET = 1 << 21, + NL80211_FEATURE_TX_POWER_INSERTION = 1 << 22, }; /** -- cgit v0.10.2 From bab5ab7d2a5466406e8003d038cc7ce6b2d5d804 Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 3 Sep 2014 15:25:01 +0300 Subject: nl80211: Add flag attribute for RRM connections Add a flag attribute to use in associations, for tagging the target connection as supporting RRM. It is the responsibility of upper layers to set this flag only if both the underlying device, and the target network indeed support RRM. To be used in ASSOCIATE and CONNECT commands. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6be68bb..a887eeb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1608,10 +1608,12 @@ struct cfg80211_auth_request { * * @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n) * @ASSOC_REQ_DISABLE_VHT: Disable VHT + * @ASSOC_REQ_USE_RRM: Declare RRM capability in this association */ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HT = BIT(0), ASSOC_REQ_DISABLE_VHT = BIT(1), + ASSOC_REQ_USE_RRM = BIT(2), }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c166d3d..de69d3d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1594,6 +1594,17 @@ enum nl80211_commands { * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. * + * @NL80211_ATTR_USE_RRM: flag for indicating whether the current connection + * shall support Radio Resource Measurements (11k). This attribute can be + * used with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests. + * User space applications are expected to use this flag only if the + * underlying device supports these minimal RRM features: + * %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES, + * %NL80211_FEATURE_QUIET, + * If this flag is used, driver must add the Power Capabilities IE to the + * association request. In addition, it must also set the RRM capability + * flag in the association request's Capability Info field. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1936,6 +1947,8 @@ enum nl80211_attrs { NL80211_ATTR_TDLS_INITIATOR, + NL80211_ATTR_USE_RRM, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d876146..459dc27 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -389,6 +389,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, + [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -6584,6 +6585,14 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) sizeof(req.vht_capa)); } + if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { + if (!(rdev->wiphy.features & + NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) || + !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) + return -EINVAL; + req.flags |= ASSOC_REQ_USE_RRM; + } + err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); if (!err) { wdev_lock(dev->ieee80211_ptr); @@ -7241,6 +7250,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) sizeof(connect.vht_capa)); } + if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) { + if (!(rdev->wiphy.features & + NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) || + !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) + return -EINVAL; + connect.flags |= ASSOC_REQ_USE_RRM; + } + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); -- cgit v0.10.2 From cd2f5dd709daa8a70f9eb408025dbb1c804929a8 Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 3 Sep 2014 15:25:02 +0300 Subject: mac80211: Add RRM support to assoc request In case of a RRM-supporting connection, in the association request frame: set the RRM capability flag, and add the required IEs. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b9d9508..6b7bdd8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -355,6 +355,7 @@ enum ieee80211_sta_flags { IEEE80211_STA_DISABLE_80P80MHZ = BIT(12), IEEE80211_STA_DISABLE_160MHZ = BIT(13), IEEE80211_STA_DISABLE_WMM = BIT(14), + IEEE80211_STA_ENABLE_RRM = BIT(15), }; struct ieee80211_mgd_auth_data { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 305e510..27231ac 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -673,6 +673,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; + if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM) + capab |= WLAN_CAPABILITY_RADIO_MEASURE; + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); @@ -738,16 +741,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } } - if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { - /* 1. power capabilities */ + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT || + capab & WLAN_CAPABILITY_RADIO_MEASURE) { pos = skb_put(skb, 4); *pos++ = WLAN_EID_PWR_CAPABILITY; *pos++ = 2; *pos++ = 0; /* min tx power */ /* max tx power */ *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def); + } - /* 2. supported channels */ + if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { /* TODO: get this in reg domain format */ pos = skb_put(skb, 2 * sband->n_channels + 2); *pos++ = WLAN_EID_SUPPORTED_CHANNELS; @@ -4410,6 +4414,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED; } + if (req->flags & ASSOC_REQ_USE_RRM) + ifmgd->flags |= IEEE80211_STA_ENABLE_RRM; + else + ifmgd->flags &= ~IEEE80211_STA_ENABLE_RRM; + if (req->crypto.control_port) ifmgd->flags |= IEEE80211_STA_CONTROL_PORT; else -- cgit v0.10.2 From a62a1aed3733d7ec6489adca4c2f69881d78cfd6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 3 Sep 2014 15:25:03 +0300 Subject: cfg80211: avoid duplicate entries on regdomain intersection The regdom intersection code simply tries intersecting each rule of the source with each rule of the target. Since the resulting intersections are not observed as a whole, this can result in multiple overlapping/duplicate entries. Make the rule addition a bit more smarter, by looking for rules that can be contained within other rules, and adding only extended ones. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8bfc9b1..b725a31 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -799,6 +799,57 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, return 0; } +/* check whether old rule contains new rule */ +static bool rule_contains(struct ieee80211_reg_rule *r1, + struct ieee80211_reg_rule *r2) +{ + /* for simplicity, currently consider only same flags */ + if (r1->flags != r2->flags) + return false; + + /* verify r1 is more restrictive */ + if ((r1->power_rule.max_antenna_gain > + r2->power_rule.max_antenna_gain) || + r1->power_rule.max_eirp > r2->power_rule.max_eirp) + return false; + + /* make sure r2's range is contained within r1 */ + if (r1->freq_range.start_freq_khz > r2->freq_range.start_freq_khz || + r1->freq_range.end_freq_khz < r2->freq_range.end_freq_khz) + return false; + + /* and finally verify that r1.max_bw >= r2.max_bw */ + if (r1->freq_range.max_bandwidth_khz < + r2->freq_range.max_bandwidth_khz) + return false; + + return true; +} + +/* add or extend current rules. do nothing if rule is already contained */ +static void add_rule(struct ieee80211_reg_rule *rule, + struct ieee80211_reg_rule *reg_rules, u32 *n_rules) +{ + struct ieee80211_reg_rule *tmp_rule; + int i; + + for (i = 0; i < *n_rules; i++) { + tmp_rule = ®_rules[i]; + /* rule is already contained - do nothing */ + if (rule_contains(tmp_rule, rule)) + return; + + /* extend rule if possible */ + if (rule_contains(rule, tmp_rule)) { + memcpy(tmp_rule, rule, sizeof(*rule)); + return; + } + } + + memcpy(®_rules[*n_rules], rule, sizeof(*rule)); + (*n_rules)++; +} + /** * regdom_intersect - do the intersection between two regulatory domains * @rd1: first regulatory domain @@ -818,12 +869,10 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, { int r, size_of_regd; unsigned int x, y; - unsigned int num_rules = 0, rule_idx = 0; + unsigned int num_rules = 0; const struct ieee80211_reg_rule *rule1, *rule2; - struct ieee80211_reg_rule *intersected_rule; + struct ieee80211_reg_rule intersected_rule; struct ieee80211_regdomain *rd; - /* This is just a dummy holder to help us count */ - struct ieee80211_reg_rule dummy_rule; if (!rd1 || !rd2) return NULL; @@ -841,7 +890,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, for (y = 0; y < rd2->n_reg_rules; y++) { rule2 = &rd2->reg_rules[y]; if (!reg_rules_intersect(rd1, rd2, rule1, rule2, - &dummy_rule)) + &intersected_rule)) num_rules++; } } @@ -856,34 +905,24 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, if (!rd) return NULL; - for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) { + for (x = 0; x < rd1->n_reg_rules; x++) { rule1 = &rd1->reg_rules[x]; - for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) { + for (y = 0; y < rd2->n_reg_rules; y++) { rule2 = &rd2->reg_rules[y]; - /* - * This time around instead of using the stack lets - * write to the target rule directly saving ourselves - * a memcpy() - */ - intersected_rule = &rd->reg_rules[rule_idx]; r = reg_rules_intersect(rd1, rd2, rule1, rule2, - intersected_rule); + &intersected_rule); /* * No need to memset here the intersected rule here as * we're not using the stack anymore */ if (r) continue; - rule_idx++; - } - } - if (rule_idx != num_rules) { - kfree(rd); - return NULL; + add_rule(&intersected_rule, rd->reg_rules, + &rd->n_reg_rules); + } } - rd->n_reg_rules = num_rules; rd->alpha2[0] = '9'; rd->alpha2[1] = '8'; rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, -- cgit v0.10.2 From 24ecd45e2eb194dcadefeb60a16f4ca751402413 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 3 Sep 2014 15:25:05 +0300 Subject: mac80211: adjust roc duration when combining ROCs The new duration (remaining duration after the current ROC ends) was calculated but not used, making the optimization worthless. Signed-off-by: Eliad Peller Reviewed-by: Ilan Peer Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d7f437e..4e57b67 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2496,6 +2496,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, if (new_dur > 0) { /* add right after tmp */ + roc->duration = new_dur; list_add(&roc->list, &tmp->list); } else { list_add_tail(&roc->list, -- cgit v0.10.2 From eaa336b0f5087addb32217e6a70845ed57249f76 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 3 Sep 2014 15:25:06 +0300 Subject: mac80211: combine roc with the "next roc" if possible If the remaining time in the current roc is not long enough, mac80211 adds the new roc right after it (if they have similar params). However, in case of multiple rocs, the "next roc" is not considered, resulting in multiple rocs, each one with its own duration. Refactor the code a bit and consider the next roc, so a single max roc will be used instead of multiple rocs (which might last much longer). Signed-off-by: Eliad Peller Reviewed-by: Ilan Peer Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4e57b67..4c1681b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2352,6 +2352,58 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, return 0; } +static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local, + struct ieee80211_roc_work *new_roc, + struct ieee80211_roc_work *cur_roc) +{ + unsigned long j = jiffies; + unsigned long cur_roc_end = cur_roc->hw_start_time + + msecs_to_jiffies(cur_roc->duration); + struct ieee80211_roc_work *next_roc; + int new_dur; + + if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun)) + return false; + + if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end)) + return false; + + ieee80211_handle_roc_started(new_roc); + + new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j); + + /* cur_roc is long enough - add new_roc to the dependents list. */ + if (new_dur <= 0) { + list_add_tail(&new_roc->list, &cur_roc->dependents); + return true; + } + + new_roc->duration = new_dur; + + /* + * if cur_roc was already coalesced before, we might + * want to extend the next roc instead of adding + * a new one. + */ + next_roc = list_entry(cur_roc->list.next, + struct ieee80211_roc_work, list); + if (&next_roc->list != &local->roc_list && + next_roc->chan == new_roc->chan && + next_roc->sdata == new_roc->sdata && + !WARN_ON(next_roc->started)) { + list_add_tail(&new_roc->list, &next_roc->dependents); + next_roc->duration = max(next_roc->duration, + new_roc->duration); + next_roc->type = max(next_roc->type, new_roc->type); + return true; + } + + /* add right after cur_roc */ + list_add(&new_roc->list, &cur_roc->list); + + return true; +} + static int ieee80211_start_roc_work(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel, @@ -2457,8 +2509,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, /* If it has already started, it's more difficult ... */ if (local->ops->remain_on_channel) { - unsigned long j = jiffies; - /* * In the offloaded ROC case, if it hasn't begun, add * this new one to the dependent list to be handled @@ -2481,29 +2531,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, break; } - if (time_before(j + IEEE80211_ROC_MIN_LEFT, - tmp->hw_start_time + - msecs_to_jiffies(tmp->duration))) { - int new_dur; - - ieee80211_handle_roc_started(roc); - - new_dur = roc->duration - - jiffies_to_msecs(tmp->hw_start_time + - msecs_to_jiffies( - tmp->duration) - - j); - - if (new_dur > 0) { - /* add right after tmp */ - roc->duration = new_dur; - list_add(&roc->list, &tmp->list); - } else { - list_add_tail(&roc->list, - &tmp->dependents); - } + if (ieee80211_coalesce_started_roc(local, roc, tmp)) queued = true; - } } else if (del_timer_sync(&tmp->work.timer)) { unsigned long new_end; -- cgit v0.10.2 From 3057dbfdab1b86a77ed6d512fc857b032f78663b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Sep 2014 23:57:40 +0200 Subject: cfg80211: enable dynack through nl80211 Enable ACK timeout estimation algorithm (dynack) using mac80211 set_coverage_class API. Dynack is activated passing coverage class equals to -1 to lower drivers and it is automatically disabled setting valid value for coverage class. Define NL80211_ATTR_WIPHY_DYN_ACK flag attribute to enable dynack from userspace. In order to activate dynack NL80211_FEATURE_ACKTO_ESTIMATION feature flag must be set by lower drivers to indicate dynack capability. Signed-off-by: Lorenzo Bianconi Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a887eeb..0d17ec9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1805,6 +1805,7 @@ struct cfg80211_connect_params { * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed + * @WIPHY_PARAM_DYN_ACK: dynack has been enabled */ enum wiphy_params_flags { WIPHY_PARAM_RETRY_SHORT = 1 << 0, @@ -1812,6 +1813,7 @@ enum wiphy_params_flags { WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, + WIPHY_PARAM_DYN_ACK = 1 << 5, }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index de69d3d..29c4399 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1605,6 +1605,12 @@ enum nl80211_commands { * association request. In addition, it must also set the RRM capability * flag in the association request's Capability Info field. * + * @NL80211_ATTR_WIPHY_DYN_ACK: flag attribute used to enable ACK timeout + * estimation algorithm (dynack). In order to activate dynack + * %NL80211_FEATURE_ACKTO_ESTIMATION feature flag must be set by lower + * drivers to indicate dynack capability. Dynack is automatically disabled + * setting valid value for coverage class. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1949,6 +1955,8 @@ enum nl80211_attrs { NL80211_ATTR_USE_RRM, + NL80211_ATTR_WIPHY_DYN_ACK, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3991,6 +3999,9 @@ enum nl80211_ap_sme_features { * current tx power value into the TPC Report IE in the spectrum * management TPC Report action frame, and in the Radio Measurement Link * Measurement Report action frame. + * @NL80211_FEATURE_ACKTO_ESTIMATION: This driver supports dynamic ACK timeout + * estimation (dynack). %NL80211_ATTR_WIPHY_DYN_ACK flag attribute is used + * to enable dynack. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -4016,6 +4027,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_WFA_TPC_IE_IN_PROBES = 1 << 20, NL80211_FEATURE_QUIET = 1 << 21, NL80211_FEATURE_TX_POWER_INSERTION = 1 << 22, + NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23, }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 459dc27..cf178d2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -226,6 +226,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, + [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -2239,11 +2240,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { + if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) + return -EINVAL; + coverage_class = nla_get_u8( info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); changed |= WIPHY_PARAM_COVERAGE_CLASS; } + if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) { + if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION)) + return -EOPNOTSUPP; + + changed |= WIPHY_PARAM_DYN_ACK; + } + if (changed) { u8 old_retry_short, old_retry_long; u32 old_frag_threshold, old_rts_threshold; -- cgit v0.10.2 From a4bcaf5556da649f0160e60fa7b4bb2c29801c12 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 4 Sep 2014 23:57:41 +0200 Subject: mac80211: extend set_coverage_class signature Extend mac80211 set_coverage_class API in order to enable ACK timeout estimation algorithm (dynack) passing coverage class equals to -1 to lower drivers. Synchronize set_coverage_class routine signature with mac80211 function pointer for p54, ath9k, ath9k_htc and ath5k drivers. Signed-off-by: Lorenzo Bianconi Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index b65c38f..ab2709a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -704,7 +704,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) * reset. */ static void -ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 5627917..994fff1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1722,7 +1722,7 @@ static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class) + s16 coverage_class) { struct ath9k_htc_priv *priv = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e6ac8d2..97c028e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1959,7 +1959,8 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +static void ath9k_set_coverage_class(struct ieee80211_hw *hw, + s16 coverage_class) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 7be3a48..97aeff0 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -696,7 +696,8 @@ static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, WARN(total, "tx flush timeout, unresponsive firmware"); } -static void p54_set_coverage_class(struct ieee80211_hw *dev, u8 coverage_class) +static void p54_set_coverage_class(struct ieee80211_hw *dev, + s16 coverage_class) { struct p54_common *priv = dev->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index db4975c..c6e6a68 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2673,7 +2673,9 @@ enum ieee80211_roc_type { * * @set_coverage_class: Set slot time for given coverage class as specified * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout - * accordingly. This callback is not required and may sleep. + * accordingly; coverage class equals to -1 to enable ACK timeout + * estimation algorithm (dynack). To disable dynack set valid value for + * coverage class. This callback is not required and may sleep. * * @testmode_cmd: Implement a cfg80211 test mode command. The passed @vif may * be %NULL. The callback can sleep. @@ -2957,7 +2959,7 @@ struct ieee80211_ops { int (*get_survey)(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void (*rfkill_poll)(struct ieee80211_hw *hw); - void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); + void (*set_coverage_class)(struct ieee80211_hw *hw, s16 coverage_class); #ifdef CONFIG_NL80211_TESTMODE int (*testmode_cmd)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4c1681b..101ae6c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1978,8 +1978,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return err; } - if (changed & WIPHY_PARAM_COVERAGE_CLASS) { - err = drv_set_coverage_class(local, wiphy->coverage_class); + if ((changed & WIPHY_PARAM_COVERAGE_CLASS) || + (changed & WIPHY_PARAM_DYN_ACK)) { + s16 coverage_class; + + coverage_class = changed & WIPHY_PARAM_COVERAGE_CLASS ? + wiphy->coverage_class : -1; + err = drv_set_coverage_class(local, coverage_class); if (err) return err; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 1142395..196d48c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -450,7 +450,7 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, } static inline int drv_set_coverage_class(struct ieee80211_local *local, - u8 value) + s16 value) { int ret = 0; might_sleep(); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 02ac535..38fae7e 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -672,13 +672,13 @@ DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold, ); TRACE_EVENT(drv_set_coverage_class, - TP_PROTO(struct ieee80211_local *local, u8 value), + TP_PROTO(struct ieee80211_local *local, s16 value), TP_ARGS(local, value), TP_STRUCT__entry( LOCAL_ENTRY - __field(u8, value) + __field(s16, value) ), TP_fast_assign( -- cgit v0.10.2 From f3000e1b43f164802f2a74c9de6a398943a36378 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 4 Sep 2014 22:37:55 +0300 Subject: mac80211: fix broken use of VHT/20Mhz with some APs commit "mac80211: disable 40MHz support in case of 20MHz AP" broke working VHT in 20Mhz with APs like Netgear R6300v2 which do not publish support for 40Mhz but allow use of VHT in 20Mhz. The break is because VHT is disabled once no HT cap doesn't indicate support for 40Mhz. This causes the assoc request to be sent without any VHT IE and the association is only HT due to this. For more details check out commit 4a817aa7 "mac80211: allow VHT with peers not capable of 40MHz" Fixes: 53b954ee4a71 ("mac80211: disable 40MHz support in case of 20MHz AP") Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 27231ac..f09bef7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -173,7 +173,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, if (!(ht_cap->cap_info & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) { - ret = IEEE80211_STA_DISABLE_40MHZ | IEEE80211_STA_DISABLE_VHT; + ret = IEEE80211_STA_DISABLE_40MHZ; goto out; } -- cgit v0.10.2 From 24a4e4008ca2a819c4c889163586a8a9b7a3a08d Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 3 Sep 2014 06:22:10 -0700 Subject: mac80211: split 802.11h parsing from transmit power policy Decouple the logic of parsing the 802.11d and 802.11h IEs from the part of deciding what to do about the data (messaging, clamping to 0 dBm, doing the actual setting). This paves the way for the next patch, which introduces more data sources for transmit power limitation. Signed-off-by: Steinar H. Gunderson Signed-off-by: Johannes Berg diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f09bef7..0b812a8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1171,19 +1171,21 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval)); } -static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, - struct ieee80211_channel *channel, - const u8 *country_ie, u8 country_ie_len, - const u8 *pwr_constr_elem) +static bool +ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + const u8 *country_ie, u8 country_ie_len, + const u8 *pwr_constr_elem, + int *chan_pwr, int *pwr_reduction) { struct ieee80211_country_ie_triplet *triplet; int chan = ieee80211_frequency_to_channel(channel->center_freq); - int i, chan_pwr, chan_increment, new_ap_level; + int i, chan_increment; bool have_chan_pwr = false; /* Invalid IE */ if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) - return 0; + return false; triplet = (void *)(country_ie + 3); country_ie_len -= 3; @@ -1211,7 +1213,7 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, for (i = 0; i < triplet->chans.num_channels; i++) { if (first_channel + i * chan_increment == chan) { have_chan_pwr = true; - chan_pwr = triplet->chans.max_power; + *chan_pwr = triplet->chans.max_power; break; } } @@ -1223,18 +1225,41 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, country_ie_len -= 3; } - if (!have_chan_pwr) - return 0; + if (have_chan_pwr) + *pwr_reduction = *pwr_constr_elem; + return have_chan_pwr; +} + +static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + struct ieee80211_mgmt *mgmt, + const u8 *country_ie, u8 country_ie_len, + const u8 *pwr_constr_ie) +{ + bool has_80211h_pwr = false; + int chan_pwr, pwr_reduction_80211h; + int new_ap_level; - new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); + if (country_ie && pwr_constr_ie && + mgmt->u.probe_resp.capab_info & + cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) { + has_80211h_pwr = ieee80211_find_80211h_pwr_constr( + sdata, channel, country_ie, country_ie_len, + pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h); + new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h); + } - if (sdata->ap_power_level == new_ap_level) + if (!has_80211h_pwr) return 0; sdata_info(sdata, "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", - new_ap_level, chan_pwr, *pwr_constr_elem, + new_ap_level, chan_pwr, pwr_reduction_80211h, sdata->u.mgd.bssid); + + if (sdata->ap_power_level == new_ap_level) + return 0; + sdata->ap_power_level = new_ap_level; if (__ieee80211_recalc_txpower(sdata)) return BSS_CHANGED_TXPOWER; @@ -3204,13 +3229,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rx_status->band, true); mutex_unlock(&local->sta_mtx); - if (elems.country_elem && elems.pwr_constr_elem && - mgmt->u.probe_resp.capab_info & - cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) - changed |= ieee80211_handle_pwr_constr(sdata, chan, - elems.country_elem, - elems.country_elem_len, - elems.pwr_constr_elem); + changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, + elems.country_elem, + elems.country_elem_len, + elems.pwr_constr_elem); ieee80211_bss_info_change_notify(sdata, changed); } -- cgit v0.10.2 From c8d6591752e96c550cb98b781326d72d8eedcc79 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 3 Sep 2014 06:48:37 -0700 Subject: mac80211: support DTPC IE (from Cisco Client eXtensions) Linux already supports 802.11h, where the access point can tell the client to reduce its transmission power. However, 802.11h is only defined for 5 GHz, where the need for this is much smaller than on 2.4 GHz. Cisco has their own solution, called DTPC (Dynamic Transmit Power Control). Cisco APs on a controller sometimes but not always send 802.11h; they always send DTPC, even on 2.4 GHz. This patch adds support for parsing and honoring the DTPC IE in addition to the 802.11h element (they do not always contain the same limits, so both must be honored); the format is not documented, but very simple. Tested (on top of wireless.git and on 3.16.1) against a Cisco Aironet 1142 joined to a Cisco 2504 WLC, by setting various transmit power levels for the given access points and observing the results. The Wireshark 802.11 dissector agrees with the interpretation of the element, except for negative numbers, which seem to never happen anyway. Signed-off-by: Steinar H. Gunderson Signed-off-by: Johannes Berg diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 77d4f26..61a09f0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1824,7 +1824,8 @@ enum ieee80211_eid { WLAN_EID_DMG_TSPEC = 146, WLAN_EID_DMG_AT = 147, WLAN_EID_DMG_CAP = 148, - /* 149-150 reserved for Cisco */ + /* 149 reserved for Cisco */ + WLAN_EID_CISCO_VENDOR_SPECIFIC = 150, WLAN_EID_DMG_OPERATION = 151, WLAN_EID_DMG_BSS_PARAM_CHANGE = 152, WLAN_EID_DMG_BEAM_REFINEMENT = 153, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6b7bdd8..c2aaec4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1369,6 +1369,7 @@ struct ieee802_11_elems { const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; const u8 *country_elem; const u8 *pwr_constr_elem; + const u8 *cisco_dtpc_elem; const struct ieee80211_timeout_interval_ie *timeout_int; const u8 *opmode_notif; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0b812a8..a7b92f5 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1230,14 +1230,30 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata, return have_chan_pwr; } +static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *channel, + const u8 *cisco_dtpc_ie, + int *pwr_level) +{ + /* From practical testing, the first data byte of the DTPC element + * seems to contain the requested dBm level, and the CLI on Cisco + * APs clearly state the range is -127 to 127 dBm, which indicates + * a signed byte, although it seemingly never actually goes negative. + * The other byte seems to always be zero. + */ + *pwr_level = (__s8)cisco_dtpc_ie[4]; +} + static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel, struct ieee80211_mgmt *mgmt, const u8 *country_ie, u8 country_ie_len, - const u8 *pwr_constr_ie) + const u8 *pwr_constr_ie, + const u8 *cisco_dtpc_ie) { - bool has_80211h_pwr = false; - int chan_pwr, pwr_reduction_80211h; + bool has_80211h_pwr = false, has_cisco_pwr = false; + int chan_pwr = 0, pwr_reduction_80211h = 0; + int pwr_level_cisco, pwr_level_80211h; int new_ap_level; if (country_ie && pwr_constr_ie && @@ -1246,16 +1262,35 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, has_80211h_pwr = ieee80211_find_80211h_pwr_constr( sdata, channel, country_ie, country_ie_len, pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h); - new_ap_level = max_t(int, 0, chan_pwr - pwr_reduction_80211h); + pwr_level_80211h = + max_t(int, 0, chan_pwr - pwr_reduction_80211h); + } + + if (cisco_dtpc_ie) { + ieee80211_find_cisco_dtpc( + sdata, channel, cisco_dtpc_ie, &pwr_level_cisco); + has_cisco_pwr = true; } - if (!has_80211h_pwr) + if (!has_80211h_pwr && !has_cisco_pwr) return 0; - sdata_info(sdata, - "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", - new_ap_level, chan_pwr, pwr_reduction_80211h, - sdata->u.mgd.bssid); + /* If we have both 802.11h and Cisco DTPC, apply both limits + * by picking the smallest of the two power levels advertised. + */ + if (has_80211h_pwr && + (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) { + sdata_info(sdata, + "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", + pwr_level_80211h, chan_pwr, pwr_reduction_80211h, + sdata->u.mgd.bssid); + new_ap_level = pwr_level_80211h; + } else { /* has_cisco_pwr is always true here. */ + sdata_info(sdata, + "Limiting TX power to %d dBm as advertised by %pM\n", + pwr_level_cisco, sdata->u.mgd.bssid); + new_ap_level = pwr_level_cisco; + } if (sdata->ap_power_level == new_ap_level) return 0; @@ -2923,7 +2958,9 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, /* * This is the canonical list of information elements we care about, * the filter code also gives us all changes to the Microsoft OUI - * (00:50:F2) vendor IE which is used for WMM which we need to track. + * (00:50:F2) vendor IE which is used for WMM which we need to track, + * as well as the DTPC IE (part of the Cisco OUI) used for signaling + * changes to requested client power. * * We implement beacon filtering in software since that means we can * avoid processing the frame here and in cfg80211, and userspace @@ -3232,7 +3269,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, elems.country_elem, elems.country_elem_len, - elems.pwr_constr_elem); + elems.pwr_constr_elem, + elems.cisco_dtpc_elem); ieee80211_bss_info_change_notify(sdata, changed); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b444f27..3c61060 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1015,6 +1015,31 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, } elems->pwr_constr_elem = pos; break; + case WLAN_EID_CISCO_VENDOR_SPECIFIC: + /* Lots of different options exist, but we only care + * about the Dynamic Transmit Power Control element. + * First check for the Cisco OUI, then for the DTPC + * tag (0x00). + */ + if (elen < 4) { + elem_parse_failed = true; + break; + } + + if (pos[0] != 0x00 || pos[1] != 0x40 || + pos[2] != 0x96 || pos[3] != 0x00) + break; + + if (elen != 6) { + elem_parse_failed = true; + break; + } + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + elems->cisco_dtpc_elem = pos; + break; case WLAN_EID_TIMEOUT_INTERVAL: if (elen >= sizeof(struct ieee80211_timeout_interval_ie)) elems->timeout_int = (void *)pos; -- cgit v0.10.2 From b1e9be8775b85d761cdb91386200a04d741f6a0d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Sep 2014 11:22:42 +0200 Subject: mac80211: annotate MMIC head/tailroom warning This message occasionally triggers for some people as in https://bugzilla.redhat.com/show_bug.cgi?id=1111740 but it's not clear which (headroom or tailroom) is at fault. Annotate the message a bit to get more information. Signed-off-by: Johannes Berg diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f7d4ca4..983527a 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -64,8 +64,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) if (!info->control.hw_key) tail += IEEE80211_TKIP_ICV_LEN; - if (WARN_ON(skb_tailroom(skb) < tail || - skb_headroom(skb) < IEEE80211_TKIP_IV_LEN)) + if (WARN(skb_tailroom(skb) < tail || + skb_headroom(skb) < IEEE80211_TKIP_IV_LEN, + "mmic: not enough head/tail (%d/%d,%d/%d)\n", + skb_headroom(skb), IEEE80211_TKIP_IV_LEN, + skb_tailroom(skb), tail)) return TX_DROP; key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; -- cgit v0.10.2 From 72c6fb915ff2d30ae14053edee4f0d30019bad76 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:51 +0300 Subject: Bluetooth: Fix incorrect LE CoC PDU length restriction based on HCI MTU The l2cap_create_le_flowctl_pdu() function that l2cap_segment_le_sdu() calls is perfectly capable of doing packet fragmentation if given bigger PDUs than the HCI buffers allow. Forcing the PDU length based on the HCI MTU (conn->mtu) would therefore needlessly strict operation on hardware with limited LE buffers (e.g. both Intel and Broadcom seem to have this set to just 27 bytes). This patch removes the restriction and makes it possible to send PDUs of the full length that the remote MPS value allows. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4a90438..52b5680 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2358,12 +2358,8 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan, BT_DBG("chan %p, msg %p, len %zu", chan, msg, len); - pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE; - - pdu_len = min_t(size_t, pdu_len, chan->remote_mps); - sdu_len = len; - pdu_len -= L2CAP_SDULEN_SIZE; + pdu_len = chan->remote_mps - L2CAP_SDULEN_SIZE; while (len > 0) { if (len <= pdu_len) -- cgit v0.10.2 From b3ed6c63f7d4a51b01a61b10e53a2992ad26aa78 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:52 +0300 Subject: Bluetooth: Remove unnecessary l2cap_chan_unlock before l2cap_chan_add The l2cap_chan_add() function doesn't require the channel to be unlocked. It only requires the l2cap_conn to be unlocked. Therefore, it's unnecessary to unlock a channel before calling l2cap_chan_add(). This patch removes such unnecessary unlocking from the l2cap_chan_connect() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 52b5680..777c41d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7078,9 +7078,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bacpy(&chan->src, &hcon->src); chan->src_type = bdaddr_type(hcon, hcon->src_type); - l2cap_chan_unlock(chan); l2cap_chan_add(conn, chan); - l2cap_chan_lock(chan); /* l2cap_chan_add takes its own ref so we can drop this one */ hci_conn_drop(hcon); -- cgit v0.10.2 From c16900cf285ca240f0f84117bf8b88a03c55469b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:17:06 +0300 Subject: Bluetooth: Fix hci_conn reference counting for fixed channels Now that SMP has been converted to use fixed channels we've got a bit of a problem with the hci_conn reference counting. So far the L2CAP code has kept a reference for each L2CAP channel that was notified of the connection. With SMP however this would mean that the connection is never dropped even though there are no other users of it. Furthermore, SMP already does its own hci_conn reference counting internally, starting from a security or pairing request and ending with the key distribution. This patch makes L2CAP fixed channels default to the L2CAP core not keeping a hci_conn reference for them. A new FLAG_HOLD_HCI_CONN flag is added so that L2CAP users can declare an exception to this rule and hold a reference even for their fixed channels. One such exception is the L2CAP socket layer which does want a reference for each socket (e.g. an ATT socket which uses a fixed channel). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index cedda39..1558ecc 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -711,6 +711,7 @@ enum { FLAG_DEFER_SETUP, FLAG_LE_CONN_REQ_SENT, FLAG_PENDING_SECURITY, + FLAG_HOLD_HCI_CONN, }; enum { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 777c41d..a655922 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -546,7 +546,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_chan_hold(chan); - hci_conn_hold(conn->hcon); + /* Only keep a reference for fixed channels if they requested it */ + if (chan->chan_type != L2CAP_CHAN_FIXED || + test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) + hci_conn_hold(conn->hcon); list_add(&chan->list, &conn->chan_l); } @@ -577,7 +580,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) chan->conn = NULL; - if (chan->scid != L2CAP_CID_A2MP) + /* Reference was only held for non-fixed channels or + * fixed channels that explicitly requested it using the + * FLAG_HOLD_HCI_CONN flag. + */ + if (chan->chan_type != L2CAP_CHAN_FIXED || + test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) hci_conn_drop(conn->hcon); if (mgr && mgr->bredr_chan == chan) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ed06f88..31f106e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -146,6 +146,14 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) case L2CAP_CHAN_RAW: chan->sec_level = BT_SECURITY_SDP; break; + case L2CAP_CHAN_FIXED: + /* Fixed channels default to the L2CAP core not holding a + * hci_conn reference for them. For fixed channels mapping to + * L2CAP sockets we do want to hold a reference so set the + * appropriate flag to request it. + */ + set_bit(FLAG_HOLD_HCI_CONN, &chan->flags); + break; } bacpy(&chan->src, &la.l2_bdaddr); -- cgit v0.10.2 From 08853f18eafe65aa97deb464c28505a67c898b0e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:55 +0300 Subject: Bluetooth: Set addr_type only when it's needed In the hci_le_conn_complete_evt() function there's no need to set the addr_type value until it's actually needed, i.e. for the black list lookup. This patch moves the code a bit further down in the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3a99f30..e8f35a9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4193,16 +4193,16 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = irk->addr_type; } - if (conn->dst_type == ADDR_LE_DEV_PUBLIC) - addr_type = BDADDR_LE_PUBLIC; - else - addr_type = BDADDR_LE_RANDOM; - if (ev->status) { hci_le_conn_failed(conn, ev->status); goto unlock; } + if (conn->dst_type == ADDR_LE_DEV_PUBLIC) + addr_type = BDADDR_LE_PUBLIC; + else + addr_type = BDADDR_LE_RANDOM; + /* Drop the connection if the device is blocked */ if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { hci_conn_drop(conn); -- cgit v0.10.2 From 5477610fc187d4aae0f699d21dfb0e3f440f7de7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:56 +0300 Subject: Bluetooth: Optimize connection parameter lookup for LE connections When we get an LE connection complete event there's really no reason to look through the entire connection parameter list as the entry should be present in the hdev->pend_le_conns list too. This patch changes the lookup code to do a more restricted lookup only in the pend_le_conns list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e8f35a9..d2ee162 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4225,7 +4225,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_proto_connect_cfm(conn, ev->status); - params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, + conn->dst_type); if (params) { list_del_init(¶ms->action); if (params->conn) { -- cgit v0.10.2 From 51bb8457ddfa74ede52bf8c02054dea831d59fff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:57 +0300 Subject: Bluetooth: Improve *_get() functions to return the object type It's natural to have *_get() functions that increment the reference count of an object to return the object type itself. This way it's simple to make a copy of the object pointer and increase the reference count in a single step. This patch updates two such get() functions, namely hci_conn_get() and l2cap_conn_get(), and updates the users to take advantage of the new API. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b0ded13..aa75eee 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -756,9 +756,10 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status); * _get()/_drop() in it, but require the caller to have a valid ref (FIXME). */ -static inline void hci_conn_get(struct hci_conn *conn) +static inline struct hci_conn *hci_conn_get(struct hci_conn *conn) { get_device(&conn->dev); + return conn; } static inline void hci_conn_put(struct hci_conn *conn) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1558ecc..8f1652e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -948,7 +948,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); void l2cap_conn_shutdown(struct l2cap_conn *conn, int err); -void l2cap_conn_get(struct l2cap_conn *conn); +struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn); void l2cap_conn_put(struct l2cap_conn *conn); int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 6c7ecf1..1b7d605 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -915,7 +915,7 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, /* connection management */ bacpy(&session->bdaddr, bdaddr); - session->conn = conn; + session->conn = l2cap_conn_get(conn); session->user.probe = hidp_session_probe; session->user.remove = hidp_session_remove; session->ctrl_sock = ctrl_sock; @@ -941,13 +941,13 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, if (ret) goto err_free; - l2cap_conn_get(session->conn); get_file(session->intr_sock->file); get_file(session->ctrl_sock->file); *out = session; return 0; err_free: + l2cap_conn_put(session->conn); kfree(session); return ret; } @@ -1327,10 +1327,8 @@ int hidp_connection_add(struct hidp_connadd_req *req, conn = NULL; l2cap_chan_lock(chan); - if (chan->conn) { - l2cap_conn_get(chan->conn); - conn = chan->conn; - } + if (chan->conn) + conn = l2cap_conn_get(chan->conn); l2cap_chan_unlock(chan); if (!conn) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a655922..cb36169 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1695,9 +1695,10 @@ static void l2cap_conn_free(struct kref *ref) kfree(conn); } -void l2cap_conn_get(struct l2cap_conn *conn) +struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn) { kref_get(&conn->ref); + return conn; } EXPORT_SYMBOL(l2cap_conn_get); @@ -6908,8 +6909,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) kref_init(&conn->ref); hcon->l2cap_data = conn; - conn->hcon = hcon; - hci_conn_get(conn->hcon); + conn->hcon = hci_conn_get(hcon); conn->hchan = hchan; BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); -- cgit v0.10.2 From f8aaf9b65a77267f749c1af641e46c3457d50701 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 17 Aug 2014 23:28:57 +0300 Subject: Bluetooth: Fix using hci_conn_get() for hci_conn pointers Wherever we keep hci_conn pointers around we should be using hci_conn_get/put to ensure that they stay valid. This patch fixes all places violating against the principle currently. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index faff624..4ecc9d5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -595,6 +595,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) conn->dst_type); if (params && params->conn) { hci_conn_drop(params->conn); + hci_conn_put(params->conn); params->conn = NULL; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9b71459..ed60d37 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2541,6 +2541,7 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev) list_for_each_entry(p, &hdev->le_conn_params, list) { if (p->conn) { hci_conn_drop(p->conn); + hci_conn_put(p->conn); p->conn = NULL; } list_del_init(&p->action); @@ -3734,8 +3735,10 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) if (!params) return; - if (params->conn) + if (params->conn) { hci_conn_drop(params->conn); + hci_conn_put(params->conn); + } list_del(¶ms->action); list_del(¶ms->list); @@ -3767,8 +3770,10 @@ void hci_conn_params_clear_all(struct hci_dev *hdev) struct hci_conn_params *params, *tmp; list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { - if (params->conn) + if (params->conn) { hci_conn_drop(params->conn); + hci_conn_put(params->conn); + } list_del(¶ms->action); list_del(¶ms->list); kfree(params); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d2ee162..e6a496a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4231,6 +4231,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) list_del_init(¶ms->action); if (params->conn) { hci_conn_drop(params->conn); + hci_conn_put(params->conn); params->conn = NULL; } } @@ -4322,7 +4323,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, * the parameters get removed and keep the reference * count consistent once the connection is established. */ - params->conn = conn; + params->conn = hci_conn_get(conn); return; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c245743..d8c6666 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3063,6 +3063,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) conn->disconn_cfm_cb = NULL; hci_conn_drop(conn); + hci_conn_put(conn); mgmt_pending_remove(cmd); } @@ -3212,7 +3213,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } conn->io_capability = cp->io_cap; - cmd->user_data = conn; + cmd->user_data = hci_conn_get(conn); if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) && hci_conn_security(conn, sec_level, auth_type, true)) @@ -4914,6 +4915,7 @@ static void get_conn_info_complete(struct pending_cmd *cmd, void *data) match->mgmt_status, &rp, sizeof(rp)); hci_conn_drop(conn); + hci_conn_put(conn); mgmt_pending_remove(cmd); } @@ -5070,7 +5072,7 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, } hci_conn_hold(conn); - cmd->user_data = conn; + cmd->user_data = hci_conn_get(conn); conn->conn_info_timestamp = jiffies; } else { @@ -5134,8 +5136,10 @@ send_rsp: cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status), &rp, sizeof(rp)); mgmt_pending_remove(cmd); - if (conn) + if (conn) { hci_conn_drop(conn); + hci_conn_put(conn); + } unlock: hci_dev_unlock(hdev); @@ -5198,7 +5202,7 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data, if (conn) { hci_conn_hold(conn); - cmd->user_data = conn; + cmd->user_data = hci_conn_get(conn); hci_cp.handle = cpu_to_le16(conn->handle); hci_cp.which = 0x01; /* Piconet clock */ -- cgit v0.10.2 From f6c63249698aaa87399e795adcf3b70171384dc2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 15 Aug 2014 21:06:59 +0300 Subject: Bluetooth: Refactor connection parameter freeing into its own function The necessary steps for freeing connection paramaters have grown quite a bit so we can simplify the code by factoring it out into its own function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ed60d37..0d3782a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3726,15 +3726,8 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, return 0; } -/* This function requires the caller holds hdev->lock */ -void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +static void hci_conn_params_free(struct hci_conn_params *params) { - struct hci_conn_params *params; - - params = hci_conn_params_lookup(hdev, addr, addr_type); - if (!params) - return; - if (params->conn) { hci_conn_drop(params->conn); hci_conn_put(params->conn); @@ -3743,6 +3736,18 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) list_del(¶ms->action); list_del(¶ms->list); kfree(params); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (!params) + return; + + hci_conn_params_free(params); hci_update_background_scan(hdev); @@ -3769,15 +3774,8 @@ void hci_conn_params_clear_all(struct hci_dev *hdev) { struct hci_conn_params *params, *tmp; - list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { - if (params->conn) { - hci_conn_drop(params->conn); - hci_conn_put(params->conn); - } - list_del(¶ms->action); - list_del(¶ms->list); - kfree(params); - } + list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) + hci_conn_params_free(params); hci_update_background_scan(hdev); -- cgit v0.10.2 From eb78d7e53d144995b9e023b151de19fa40af72f3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 00:41:41 +0300 Subject: Bluetooth: Use zero timeout for immediate scheduling There's no point in passing a "small" timeout to queue_delayed_work() to try to get the callback faster scheduled. Passing 0 is perfectly valid and will cause a shortcut to a direct queue_work(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index aa75eee..18c24f6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -791,7 +791,7 @@ static inline void hci_conn_drop(struct hci_conn *conn) if (!conn->out) timeo *= 2; } else { - timeo = msecs_to_jiffies(10); + timeo = 0; } break; @@ -800,7 +800,7 @@ static inline void hci_conn_drop(struct hci_conn *conn) break; default: - timeo = msecs_to_jiffies(10); + timeo = 0; break; } -- cgit v0.10.2 From 6c388d32ec1b9fcc2f2404fb5e9b3b0096be5de9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 00:41:42 +0300 Subject: Bluetooth: Fix hci_conn reference counting with hci_chan The hci_chan_del() function was doing a hci_conn_drop() but there was no matching hci_conn_hold() in the hci_chan_create() function. Furthermore, as the hci_chan struct holds a pointer to the hci_conn there should be proper use of hci_conn_get/put. This patch fixes both issues so that hci_chan does correct reference counting of the hci_conn object. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 4ecc9d5..7815826 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1295,7 +1295,8 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) if (!chan) return NULL; - chan->conn = conn; + chan->conn = hci_conn_get(conn); + hci_conn_hold(conn); skb_queue_head_init(&chan->data_q); chan->state = BT_CONNECTED; @@ -1316,6 +1317,7 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); hci_conn_drop(conn); + hci_conn_put(conn); skb_queue_purge(&chan->data_q); kfree(chan); -- cgit v0.10.2 From b3ff670a44cc34c01e78900c42255511e4f232e6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 00:41:43 +0300 Subject: Bluetooth: Set disc_timeout to 0 when calling hci_chan_del The hci_chan_del() function is used in scenarios where we've decided we want to get rid of the underlying baseband link. It makes therefore sense to force the disc_timeout to 0 so that the disconnection routines are immediately scheduled. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7815826..cb04a4e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1316,6 +1316,9 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); + /* Force the connection to be immediately dropped */ + conn->disc_timeout = 0; + hci_conn_drop(conn); hci_conn_put(conn); -- cgit v0.10.2 From f94b665dcf15324f5ac8aa639e47be0829b6409d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 00:41:44 +0300 Subject: Bluetooth: Ignore incoming data after initiating disconnection When hci_chan_del is called the disconnection routines get scheduled through a workqueue. If there's any incoming ACL data before the routines get executed there's a chance that a new hci_chan is created and the disconnection never happens. This patch adds a new hci_conn flag to indicate that we're in the process of driving the connection down. We set the flag in hci_chan_del and check for it in hci_chan_create so that no new channels are created for the same connection. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 18c24f6..dbe7364 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -553,6 +553,7 @@ enum { HCI_CONN_FIPS, HCI_CONN_STK_ENCRYPT, HCI_CONN_AUTH_INITIATOR, + HCI_CONN_DROP, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cb04a4e..aaa7e38 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1291,6 +1291,11 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s hcon %p", hdev->name, conn); + if (test_bit(HCI_CONN_DROP, &conn->flags)) { + BT_DBG("Refusing to create new hci_chan"); + return NULL; + } + chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return NULL; @@ -1318,6 +1323,7 @@ void hci_chan_del(struct hci_chan *chan) /* Force the connection to be immediately dropped */ conn->disc_timeout = 0; + set_bit(HCI_CONN_DROP, &conn->flags); hci_conn_drop(conn); hci_conn_put(conn); -- cgit v0.10.2 From bcbb655a180344d8004ede669228992bff1921e4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:27 +0300 Subject: Bluetooth: Remove hci_conn_hold/drop from hci_chan We can't have hci_chan contribute to the "active" reference counting of the hci_conn since otherwise the connection would never get dropped when there are no more users (since hci_chan would be counted as a user). This patch removes hold() when creating the hci_chan and drop() when destroying it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index aaa7e38..5157a09 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1301,7 +1301,6 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) return NULL; chan->conn = hci_conn_get(conn); - hci_conn_hold(conn); skb_queue_head_init(&chan->data_q); chan->state = BT_CONNECTED; @@ -1321,11 +1320,9 @@ void hci_chan_del(struct hci_chan *chan) synchronize_rcu(); - /* Force the connection to be immediately dropped */ - conn->disc_timeout = 0; + /* Prevent new hci_chan's to be created for this hci_conn */ set_bit(HCI_CONN_DROP, &conn->flags); - hci_conn_drop(conn); hci_conn_put(conn); skb_queue_purge(&chan->data_q); -- cgit v0.10.2 From e31fb86005a01b7df8427b09d0158da28d0c773a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:28 +0300 Subject: Bluetooth: Set discon_timeout to 0 in l2cap_conn_del When the l2cap_conn_del() function is used we do not want to wait around "in case something happens" before disconnecting. This patch sets the disconnection timeout to 0 so that the disconnection routines get immediately scheduled. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cb36169..2d550af 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1640,6 +1640,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_unregister_all_users(conn); + /* Force the connection to be immediately dropped */ + hcon->disc_timeout = 0; + mutex_lock(&conn->chan_lock); /* Kill channels */ -- cgit v0.10.2 From 1e91c29eb60c031f4297d1a58125d0bd37691348 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:29 +0300 Subject: Bluetooth: Use hci_disconnect for immediate disconnection from SMP Relying on the l2cap_conn_del procedure (triggered through the l2cap_conn_shutdown API) to get the connection disconnected is not reliable as it depends on all users releasing (through hci_conn_drop) and that there's at least one user (so hci_conn_drop is called at least one time). A much simpler and more reliable solution is to call hci_disconnect() directly from the SMP code when we want to disconnect. One side-effect this has is that it prevents any SMP Failure PDU from being sent before the disconnection, however neither one of the scenarios where l2cap_conn_shutdown was used really requires this. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 07ca4ce..4965849 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -829,7 +829,7 @@ static void smp_timeout(struct work_struct *work) BT_DBG("conn %p", conn); - l2cap_conn_shutdown(conn, ETIMEDOUT); + hci_disconnect(conn->hcon, HCI_ERROR_REMOTE_USER_TERM); } static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) @@ -1569,7 +1569,7 @@ static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) if (smp) cancel_delayed_work_sync(&smp->security_timer); - l2cap_conn_shutdown(chan->conn, -err); + hci_disconnect(chan->conn->hcon, HCI_ERROR_AUTH_FAILURE); } return err; -- cgit v0.10.2 From b04afa0c280b7e7ced88692251d75a78c8fcb2a7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:30 +0300 Subject: Bluetooth: Remove unused l2cap_conn_shutdown API Now that there are no more users of the l2cap_conn_shutdown API (since smp.c switched to using hci_disconnect) we can simply remove it along with all of it's l2cap_conn variables. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8f1652e..be25edd 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -625,9 +625,6 @@ struct l2cap_conn { struct delayed_work info_timer; - int disconn_err; - struct work_struct disconn_work; - struct sk_buff *rx_skb; __u32 rx_len; __u8 tx_ident; @@ -947,7 +944,6 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); -void l2cap_conn_shutdown(struct l2cap_conn *conn, int err); struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn); void l2cap_conn_put(struct l2cap_conn *conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2d550af..2d9a2b5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1635,9 +1635,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (work_pending(&conn->pending_rx_work)) cancel_work_sync(&conn->pending_rx_work); - if (work_pending(&conn->disconn_work)) - cancel_work_sync(&conn->disconn_work); - l2cap_unregister_all_users(conn); /* Force the connection to be immediately dropped */ @@ -1670,26 +1667,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_conn_put(conn); } -static void disconn_work(struct work_struct *work) -{ - struct l2cap_conn *conn = container_of(work, struct l2cap_conn, - disconn_work); - - BT_DBG("conn %p", conn); - - l2cap_conn_del(conn->hcon, conn->disconn_err); -} - -void l2cap_conn_shutdown(struct l2cap_conn *conn, int err) -{ - struct hci_dev *hdev = conn->hcon->hdev; - - BT_DBG("conn %p err %d", conn, err); - - conn->disconn_err = err; - queue_work(hdev->workqueue, &conn->disconn_work); -} - static void l2cap_conn_free(struct kref *ref) { struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); @@ -6943,8 +6920,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); - INIT_WORK(&conn->disconn_work, disconn_work); - skb_queue_head_init(&conn->pending_rx); INIT_WORK(&conn->pending_rx_work, process_pending_rx); -- cgit v0.10.2 From 9b7b18ef1bea82e5fc1e05da386ff57b0f60f651 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:31 +0300 Subject: Bluetooth: Fix SMP error and response to be mutually exclusive Returning failure from the SMP data parsing function will cause an immediate disconnect, making any attempts to send a response PDU futile. This patch updates the function to always either send a response or return an error, but never both at the same time: * In the case that HCI_LE_ENABLED is not set we want to send a Pairing Not Supported response but it is not required to force a disconnection, so do not set the error return in this case. * If we get garbage SMP data we can just fail with the handler function instead of also trying to send an SMP Failure PDU. * There's no reason to force a disconnection if we receive an unknown SMP command. Instead simply send a proper Command Not Supported SMP response. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4965849..16c1811 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1430,7 +1430,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) return -EILSEQ; if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { - err = -EOPNOTSUPP; reason = SMP_PAIRING_NOTSUPP; goto done; } @@ -1447,7 +1446,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); - reason = SMP_CMD_NOTSUPP; err = -EOPNOTSUPP; goto done; } @@ -1459,7 +1457,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) case SMP_CMD_PAIRING_FAIL: smp_failure(conn, 0); - reason = 0; err = -EPERM; break; @@ -1501,17 +1498,17 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) default: BT_DBG("Unknown command code 0x%2.2x", code); - reason = SMP_CMD_NOTSUPP; - err = -EOPNOTSUPP; goto done; } done: - if (reason) - smp_failure(conn, reason); - if (!err) + if (!err) { + if (reason) + smp_failure(conn, reason); kfree_skb(skb); + } + return err; } -- cgit v0.10.2 From e3b679d56caa2bc555dee646a6ac5861631e7a28 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:32 +0300 Subject: Bluetooth: Update hci_disconnect() to return an error value We'll soon use hci_disconnect() from places that are interested to know whether the hci_send_cmd() really succeeded or not. This patch updates hci_disconnect() to pass on any error returned from hci_send_cmd(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index dbe7364..2b6e04d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -703,7 +703,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, return NULL; } -void hci_disconnect(struct hci_conn *conn, __u8 reason); +int hci_disconnect(struct hci_conn *conn, __u8 reason); bool hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_sco_setup(struct hci_conn *conn, __u8 status); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5157a09..dd2df20 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -122,7 +122,7 @@ static void hci_reject_sco(struct hci_conn *conn) hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp); } -void hci_disconnect(struct hci_conn *conn, __u8 reason) +int hci_disconnect(struct hci_conn *conn, __u8 reason) { struct hci_cp_disconnect cp; @@ -132,7 +132,7 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason) cp.handle = cpu_to_le16(conn->handle); cp.reason = reason; - hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); + return hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); } static void hci_amp_disconn(struct hci_conn *conn) -- cgit v0.10.2 From e3f2f92a047cd2be3c87a2aaf0a8958e1fd4c17a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:33 +0300 Subject: Bluetooth: Use hci_disconnect() for mgmt_disconnect_device() There's no reason to custom build the HCI_Disconnect command in the Disconnect Device mgmt command handler. This patch updates the code to use hci_disconnect() instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d8c6666..ab9521a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2788,7 +2788,6 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_disconnect *cp = data; struct mgmt_rp_disconnect rp; - struct hci_cp_disconnect dc; struct pending_cmd *cmd; struct hci_conn *conn; int err; @@ -2836,10 +2835,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - dc.handle = cpu_to_le16(conn->handle); - dc.reason = HCI_ERROR_REMOTE_USER_TERM; - - err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); + err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM); if (err < 0) mgmt_pending_remove(cmd); -- cgit v0.10.2 From 839035a7b3acd17a6f739b1fb50298e9499d3fa4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 18 Aug 2014 20:33:34 +0300 Subject: Bluetooth: Move clock offset reading into hci_disconnect() To give all hci_disconnect() users the advantage of getting the clock offset read automatically this patch moves the necessary code from hci_conn_timeout() into hci_disconnect(). This way we pretty much always update the clock offset when disconnecting. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dd2df20..e3d7ae9 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -128,6 +128,19 @@ int hci_disconnect(struct hci_conn *conn, __u8 reason) BT_DBG("hcon %p", conn); + /* When we are master of an established connection and it enters + * the disconnect timeout, then go ahead and try to read the + * current clock offset. Processing of the result is done + * within the event handling and hci_clock_offset_evt function. + */ + if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) { + struct hci_dev *hdev = conn->hdev; + struct hci_cp_read_clock_offset cp; + + cp.handle = cpu_to_le16(conn->handle); + hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp); + } + conn->state = BT_DISCONN; cp.handle = cpu_to_le16(conn->handle); @@ -325,25 +338,6 @@ static void hci_conn_timeout(struct work_struct *work) hci_amp_disconn(conn); } else { __u8 reason = hci_proto_disconn_ind(conn); - - /* When we are master of an established connection - * and it enters the disconnect timeout, then go - * ahead and try to read the current clock offset. - * - * Processing of the result is done within the - * event handling and hci_clock_offset_evt function. - */ - if (conn->type == ACL_LINK && - conn->role == HCI_ROLE_MASTER) { - struct hci_dev *hdev = conn->hdev; - struct hci_cp_read_clock_offset cp; - - cp.handle = cpu_to_le16(conn->handle); - - hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, - sizeof(cp), &cp); - } - hci_disconnect(conn, reason); } break; -- cgit v0.10.2 From 434714dc02b286d3f21179c651a6f1a84e199eb7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 1 Sep 2014 09:45:03 +0300 Subject: Bluetooth: Add clarifying comment for LE CoC result value The "pending" L2CAP response value is not defined for LE CoC. This patch adds a clarifying comment to the code so that the reader will not think there is a bug in trying to use this value for LE CoC. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2d9a2b5..ab405f0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5413,6 +5413,11 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { l2cap_state_change(chan, BT_CONNECT2); + /* The following result value is actually not defined + * for LE CoC but we use it to let the function know + * that it should bail out after doing its cleanup + * instead of sending a response. + */ result = L2CAP_CR_PEND; chan->ops->defer(chan); } else { -- cgit v0.10.2 From 1b0921d6be7860271ccf6027891b8215fc28cde5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:48 +0300 Subject: Bluetooth: Remove unnecessary checks after canceling SMP security timer The SMP security timer used to be able to modify the SMP context state but now days it simply calls hci_disconnect(). It is therefore unnecessary to have extra sanity checks for the SMP context after canceling the timer. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 16c1811..b8ecc7b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -282,8 +282,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) smp = chan->data; cancel_delayed_work_sync(&smp->security_timer); - if (test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) - schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT); + schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT); } static __u8 authreq_to_seclevel(__u8 authreq) @@ -375,9 +374,6 @@ static void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); cancel_delayed_work_sync(&smp->security_timer); - /* In case the timeout freed the SMP context */ - if (!chan->data) - return; if (work_pending(&smp->distribute_work)) { cancel_work_sync(&smp->distribute_work); -- cgit v0.10.2 From 84bc0db53b3a425fb992d5fed25b575e4434167a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:49 +0300 Subject: Bluetooth: Don't take any action in smp_resume_cb if not encrypted When smp_resume_cb is called if we're not encrypted (i.e. the callback wasn't called because the connection became encrypted) we shouldn't take any action at all. This patch moves also the security_timer cancellation behind this condition. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b8ecc7b..9accb47 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1533,10 +1533,12 @@ static void smp_resume_cb(struct l2cap_chan *chan) if (!smp) return; + if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + return; + cancel_delayed_work(&smp->security_timer); - if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) - queue_work(hdev->workqueue, &smp->distribute_work); + queue_work(hdev->workqueue, &smp->distribute_work); } static void smp_ready_cb(struct l2cap_chan *chan) -- cgit v0.10.2 From f3d82d0c8ec025fc113408e3ad5775fed5a060ff Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:50 +0300 Subject: Bluetooth: Move identity address update behind a workqueue The identity address update of all channels for an l2cap_conn needs to take the lock for each channel, i.e. it's safest to do this by a separate workqueue callback. Previously this was partially solved by moving the entire SMP key distribution behind a workqueue. However, if we want SMP context locking to be correct and safe we should always use the l2cap_chan lock when accessing it, meaning even smp_distribute_keys needs to take that lock which would once again create a dead lock when updating the identity address. The simplest way to solve this is to have l2cap_conn manage the deferred work which is what this patch does. A subsequent patch will remove the now unnecessary SMP key distribution work struct. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index be25edd..ead99f0 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -633,6 +633,8 @@ struct l2cap_conn { struct sk_buff_head pending_rx; struct work_struct pending_rx_work; + struct work_struct id_addr_update_work; + __u8 disc_reason; struct l2cap_chan *smp; @@ -937,7 +939,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void l2cap_chan_del(struct l2cap_chan *chan, int err); -void l2cap_conn_update_id_addr(struct hci_conn *hcon); void l2cap_send_conn_req(struct l2cap_chan *chan); void l2cap_move_start(struct l2cap_chan *chan); void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ab405f0..b71430c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -631,9 +631,11 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } EXPORT_SYMBOL_GPL(l2cap_chan_del); -void l2cap_conn_update_id_addr(struct hci_conn *hcon) +static void l2cap_conn_update_id_addr(struct work_struct *work) { - struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + id_addr_update_work); + struct hci_conn *hcon = conn->hcon; struct l2cap_chan *chan; mutex_lock(&conn->chan_lock); @@ -1635,6 +1637,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (work_pending(&conn->pending_rx_work)) cancel_work_sync(&conn->pending_rx_work); + if (work_pending(&conn->id_addr_update_work)) + cancel_work_sync(&conn->id_addr_update_work); + l2cap_unregister_all_users(conn); /* Force the connection to be immediately dropped */ @@ -6927,6 +6932,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) skb_queue_head_init(&conn->pending_rx); INIT_WORK(&conn->pending_rx_work, process_pending_rx); + INIT_WORK(&conn->id_addr_update_work, l2cap_conn_update_id_addr); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9accb47..795c603 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -654,7 +654,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) */ bacpy(&hcon->dst, &smp->remote_irk->bdaddr); hcon->dst_type = smp->remote_irk->addr_type; - l2cap_conn_update_id_addr(hcon); + queue_work(hdev->workqueue, &conn->id_addr_update_work); /* When receiving an indentity resolving key for * a remote device that does not use a resolvable -- cgit v0.10.2 From d6268e86a12a94a4f5193551c2367162e6a37db4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:51 +0300 Subject: Bluetooth: Remove unnecessary deferred work for SMP key distribution Now that the identity address update happens through its own deferred work there's no need to have smp_distribute_keys anymore behind a second deferred work. This patch removes this extra construction and makes the code do direct calls to smp_distribute_keys() again. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 795c603..0b4403f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -46,7 +46,6 @@ enum { struct smp_chan { struct l2cap_conn *conn; struct delayed_work security_timer; - struct work_struct distribute_work; u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ @@ -375,12 +374,6 @@ static void smp_chan_destroy(struct l2cap_conn *conn) cancel_delayed_work_sync(&smp->security_timer); - if (work_pending(&smp->distribute_work)) { - cancel_work_sync(&smp->distribute_work); - if (!chan->data) - return; - } - complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(conn->hcon, complete); @@ -703,10 +696,8 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } -static void smp_distribute_keys(struct work_struct *work) +static void smp_distribute_keys(struct smp_chan *smp) { - struct smp_chan *smp = container_of(work, struct smp_chan, - distribute_work); struct smp_cmd_pairing *req, *rsp; struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; @@ -850,7 +841,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; - INIT_WORK(&smp->distribute_work, smp_distribute_keys); INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); hci_conn_hold(conn->hcon); @@ -1290,7 +1280,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) rp->ediv, rp->rand); smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - queue_work(hdev->workqueue, &smp->distribute_work); + smp_distribute_keys(smp); hci_dev_unlock(hdev); return 0; @@ -1368,7 +1358,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, smp->id_addr_type, smp->irk, &rpa); distribute: - queue_work(hdev->workqueue, &smp->distribute_work); + smp_distribute_keys(smp); hci_dev_unlock(hcon->hdev); @@ -1404,7 +1394,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; - queue_work(hdev->workqueue, &smp->distribute_work); + smp_distribute_keys(smp); hci_dev_unlock(hdev); return 0; @@ -1526,7 +1516,6 @@ static void smp_resume_cb(struct l2cap_chan *chan) struct smp_chan *smp = chan->data; struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; BT_DBG("chan %p", chan); @@ -1538,7 +1527,7 @@ static void smp_resume_cb(struct l2cap_chan *chan) cancel_delayed_work(&smp->security_timer); - queue_work(hdev->workqueue, &smp->distribute_work); + smp_distribute_keys(smp); } static void smp_ready_cb(struct l2cap_chan *chan) -- cgit v0.10.2 From fc75cc8684d21d3649b28c4c37d4ce3f000759e4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:52 +0300 Subject: Bluetooth: Fix locking of the SMP context Before the move the l2cap_chan the SMP context (smp_chan) didn't have any kind of proper locking. The best there existed was the HCI_CONN_LE_SMP_PEND flag which was used to enable mutual exclusion for potential multiple creators of the SMP context. Now that SMP has been converted to use the l2cap_chan infrastructure and since the SMP context is directly mapped to a corresponding l2cap_chan we get the SMP context locking essentially for free through the l2cap_chan lock. For all callbacks that l2cap_core.c makes for each channel implementation (smp.c in the case of SMP) the l2cap_chan lock is held through l2cap_chan_lock(chan). Since the calls from l2cap_core.c to smp.c are covered the only missing piece to have the locking implemented properly is to ensure that the lock is held for any other call path that may access the SMP context. This means user responses through mgmt.c, requests to elevate the security of a connection through hci_conn.c, as well as any deferred work through workqueues. This patch adds the necessary locking to all these other code paths that try to access the SMP context. Since mutual exclusion for the l2cap_chan access is now covered from all directions the patch also removes unnecessary HCI_CONN_LE_SMP_PEND flag (once we've acquired the chan lock we can simply check whether chan->smp is set to know if there's an SMP context). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2b6e04d..045d913 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -539,7 +539,6 @@ enum { HCI_CONN_RSWITCH_PEND, HCI_CONN_MODE_CHANGE_PEND, HCI_CONN_SCO_SETUP_PEND, - HCI_CONN_LE_SMP_PEND, HCI_CONN_MGMT_CONNECTED, HCI_CONN_SSP_ENABLED, HCI_CONN_SC_ENABLED, diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0b4403f..c71589f 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -409,7 +409,6 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp; if (reason) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), @@ -419,12 +418,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, HCI_ERROR_AUTH_FAILURE); - if (!chan->data) - return; - - smp = chan->data; - - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) + if (chan->data) smp_chan_destroy(conn); } @@ -706,9 +700,6 @@ static void smp_distribute_keys(struct smp_chan *smp) BT_DBG("conn %p", conn); - if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return; - rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ @@ -801,7 +792,6 @@ static void smp_distribute_keys(struct smp_chan *smp) if ((smp->remote_key_dist & 0x07)) return; - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -825,16 +815,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); - if (!smp) { - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); + if (!smp) return NULL; - } smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(smp->tfm_aes)) { BT_ERR("Unable to create ECB crypto context"); kfree(smp); - clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); return NULL; } @@ -854,16 +841,23 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) struct l2cap_chan *chan; struct smp_chan *smp; u32 value; + int err; BT_DBG(""); - if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) + if (!conn) return -ENOTCONN; chan = conn->smp; if (!chan) return -ENOTCONN; + l2cap_chan_lock(chan); + if (!chan->data) { + err = -ENOTCONN; + goto unlock; + } + smp = chan->data; switch (mgmt_op) { @@ -879,12 +873,16 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) case MGMT_OP_USER_PASSKEY_NEG_REPLY: case MGMT_OP_USER_CONFIRM_NEG_REPLY: smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); - return 0; + err = 0; + goto unlock; default: smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto unlock; } + err = 0; + /* If it is our turn to send Pairing Confirm, do so now */ if (test_bit(SMP_FLAG_CFM_PENDING, &smp->flags)) { u8 rsp = smp_confirm(smp); @@ -892,12 +890,15 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) smp_failure(conn, rsp); } - return 0; +unlock: + l2cap_chan_unlock(chan); + return err; } static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; + struct l2cap_chan *chan = conn->smp; struct hci_dev *hdev = conn->hcon->hdev; struct smp_chan *smp; u8 key_size, auth, sec_level; @@ -911,12 +912,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->role != HCI_ROLE_SLAVE) return SMP_CMD_NOTSUPP; - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + if (!chan->data) smp = smp_chan_create(conn); - } else { - struct l2cap_chan *chan = conn->smp; + else smp = chan->data; - } if (!smp) return SMP_UNSPECIFIED; @@ -1122,6 +1121,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; + struct l2cap_chan *chan = conn->smp; struct smp_chan *smp; u8 sec_level; @@ -1143,7 +1143,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) + /* If SMP is already in progress ignore this request */ + if (chan->data) return 0; smp = smp_chan_create(conn); @@ -1170,8 +1171,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan = conn->smp; struct smp_chan *smp; __u8 authreq; + int ret; BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level); @@ -1192,12 +1195,19 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; - if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return 0; + l2cap_chan_lock(chan); + + /* If SMP is already in progress ignore this request */ + if (chan->data) { + ret = 0; + goto unlock; + } smp = smp_chan_create(conn); - if (!smp) - return 1; + if (!smp) { + ret = 1; + goto unlock; + } authreq = seclevel_to_authreq(sec_level); @@ -1223,8 +1233,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) } set_bit(SMP_FLAG_INITIATOR, &smp->flags); + ret = 0; - return 0; +unlock: + l2cap_chan_unlock(chan); + return ret; } static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) @@ -1315,7 +1328,6 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; bdaddr_t rpa; BT_DBG(""); @@ -1430,7 +1442,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) * returns an error). */ if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && - !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { + !chan->data) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); err = -EOPNOTSUPP; goto done; @@ -1504,7 +1516,7 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) BT_DBG("chan %p", chan); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + if (chan->data) smp_chan_destroy(conn); conn->smp = NULL; -- cgit v0.10.2 From 88d3a8acf33e8f4989a1032998eb819a89829573 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:53 +0300 Subject: Bluetooth: Add define for key distribution mask This patch adds a define for the allowed bits of the key distribution mask so we don't have to have magic 0x07 constants throughout the code. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c71589f..5003d22 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -34,6 +34,7 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) #define AUTH_REQ_MASK 0x07 +#define KEY_DIST_MASK 0x07 enum { SMP_FLAG_TK_VALID, @@ -703,7 +704,7 @@ static void smp_distribute_keys(struct smp_chan *smp) rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ - if (hcon->out && (smp->remote_key_dist & 0x07)) + if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) return; req = (void *) &smp->preq[1]; @@ -789,7 +790,7 @@ static void smp_distribute_keys(struct smp_chan *smp) } /* If there are still keys to be received wait for them */ - if ((smp->remote_key_dist & 0x07)) + if (smp->remote_key_dist & KEY_DIST_MASK) return; set_bit(SMP_FLAG_COMPLETE, &smp->flags); -- cgit v0.10.2 From c6e81e9ae61cae3ea265e8f7fb2cbe59afc63594 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:54 +0300 Subject: Bluetooth: Fix calling smp_distribute_keys() when still waiting for keys When we're in the process of receiving keys in phase 3 of SMP we keep track of which keys are still expected in the smp->remote_key_dist variable. If we still have some key bits set we need to continue waiting for more PDUs and not needlessly call smp_distribute_keys(). This patch fixes two such cases in the smp_cmd_master_ident() and smp_cmd_ident_addr_info() handler functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5003d22..e76c963 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1293,7 +1293,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp->ltk = ltk; - if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + if (!(smp->remote_key_dist & KEY_DIST_MASK)) smp_distribute_keys(smp); hci_dev_unlock(hdev); @@ -1371,7 +1371,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, smp->id_addr_type, smp->irk, &rpa); distribute: - smp_distribute_keys(smp); + if (!(smp->remote_key_dist & KEY_DIST_MASK)) + smp_distribute_keys(smp); hci_dev_unlock(hcon->hdev); -- cgit v0.10.2 From b28b4943660f4e36f118b751ec606c103ba6b1cc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 5 Sep 2014 22:19:55 +0300 Subject: Bluetooth: Add strict checks for allowed SMP PDUs SMP defines quite clearly when certain PDUs are to be expected/allowed and when not, but doesn't have any explicit request/response definition. So far the code has relied on each PDU handler to behave correctly if receiving PDUs at an unexpected moment, however this requires many different checks and is prone to errors. This patch introduces a generic way to keep track of allowed PDUs and thereby reduces the responsibility & load on individual command handlers. The tracking is implemented using a simple bit-mask where each opcode maps to its own bit. If the bit is set the corresponding PDU is allow and if the bit is not set the PDU is not allowed. As a simple example, when we send the Pairing Request we'd set the bit for Pairing Response, and when we receive the Pairing Response we'd clear the bit for Pairing Response. Since the disallowed PDU rejection is now done in a single central place we need to be a bit careful of which action makes most sense to all cases. Previously some, such as Security Request, have been simply ignored whereas others have caused an explicit disconnect. The only PDU rejection action that keeps good interoperability and can be used for all the applicable use cases is to drop the data. This may raise some concerns of us now being more lenient for misbehaving (and potentially malicious) devices, but the policy of simply dropping data has been a successful one for many years e.g. in L2CAP (where this is the *only* policy for such cases - we never request disconnection in l2cap_core.c because of bad data). Furthermore, we cannot prevent connected devices from creating the SMP context (through a Security or Pairing Request), and once the context exists looking up the corresponding bit for the received opcode and deciding to reject it is essentially an equally lightweight operation as the kind of rejection that l2cap_core.c already successfully does. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index e76c963..1201670 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -31,6 +31,9 @@ #include "smp.h" +#define SMP_ALLOW_CMD(smp, code) set_bit(code, &smp->allow_cmd) +#define SMP_DISALLOW_CMD(smp, code) clear_bit(code, &smp->allow_cmd) + #define SMP_TIMEOUT msecs_to_jiffies(30000) #define AUTH_REQ_MASK 0x07 @@ -47,6 +50,7 @@ enum { struct smp_chan { struct l2cap_conn *conn; struct delayed_work security_timer; + unsigned long allow_cmd; /* Bitmask of allowed commands */ u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ @@ -553,6 +557,11 @@ static u8 smp_confirm(struct smp_chan *smp) smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); + if (conn->hcon->out) + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); + else + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); + return 0; } @@ -691,6 +700,20 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } +static void smp_allow_key_dist(struct smp_chan *smp) +{ + /* Allow the first expected phase 3 PDU. The rest of the PDUs + * will be allowed in each PDU handler to ensure we receive + * them in the correct order. + */ + if (smp->remote_key_dist & SMP_DIST_ENC_KEY) + SMP_ALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO); + else if (smp->remote_key_dist & SMP_DIST_ID_KEY) + SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO); + else if (smp->remote_key_dist & SMP_DIST_SIGN) + SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO); +} + static void smp_distribute_keys(struct smp_chan *smp) { struct smp_cmd_pairing *req, *rsp; @@ -704,8 +727,10 @@ static void smp_distribute_keys(struct smp_chan *smp) rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ - if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) + if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) { + smp_allow_key_dist(smp); return; + } req = (void *) &smp->preq[1]; @@ -790,8 +815,10 @@ static void smp_distribute_keys(struct smp_chan *smp) } /* If there are still keys to be received wait for them */ - if (smp->remote_key_dist & KEY_DIST_MASK) + if (smp->remote_key_dist & KEY_DIST_MASK) { + smp_allow_key_dist(smp); return; + } set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -829,6 +856,8 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_FAIL); + INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); hci_conn_hold(conn->hcon); @@ -925,6 +954,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) (req->auth_req & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; + SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_REQ); + smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); @@ -958,6 +989,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->prsp[1], &rsp, sizeof(rsp)); smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); /* Request setup of TK */ ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); @@ -983,6 +1015,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; + SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RSP); + skb_pull(skb, sizeof(*rsp)); req = (void *) &smp->preq[1]; @@ -1040,13 +1074,19 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(smp->pcnf)) return SMP_INVALID_PARAMS; + SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); + memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); - if (conn->hcon->out) + if (conn->hcon->out) { smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); - else if (test_bit(SMP_FLAG_TK_VALID, &smp->flags)) + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); + return 0; + } + + if (test_bit(SMP_FLAG_TK_VALID, &smp->flags)) return smp_confirm(smp); else set_bit(SMP_FLAG_CFM_PENDING, &smp->flags); @@ -1064,6 +1104,8 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(smp->rrnd)) return SMP_INVALID_PARAMS; + SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); + memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd)); skb_pull(skb, sizeof(smp->rrnd)); @@ -1122,7 +1164,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_security_req *rp = (void *) skb->data; struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; - struct l2cap_chan *chan = conn->smp; struct smp_chan *smp; u8 sec_level; @@ -1144,10 +1185,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; - /* If SMP is already in progress ignore this request */ - if (chan->data) - return 0; - smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; @@ -1165,6 +1202,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP); return 0; } @@ -1227,10 +1265,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) memcpy(&smp->preq[1], &cp, sizeof(cp)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP); } else { struct smp_cmd_security_req cp; cp.auth_req = authreq; smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp); + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_REQ); } set_bit(SMP_FLAG_INITIATOR, &smp->flags); @@ -1252,9 +1292,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - /* Ignore this PDU if it wasn't requested */ - if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) - return 0; + SMP_DISALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO); + SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT); skb_pull(skb, sizeof(*rp)); @@ -1278,13 +1317,13 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - /* Ignore this PDU if it wasn't requested */ - if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) - return 0; - /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_ENC_KEY; + SMP_DISALLOW_CMD(smp, SMP_CMD_MASTER_IDENT); + if (smp->remote_key_dist & SMP_DIST_ID_KEY) + SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO); + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -1311,9 +1350,8 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*info)) return SMP_INVALID_PARAMS; - /* Ignore this PDU if it wasn't requested */ - if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - return 0; + SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_INFO); + SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO); skb_pull(skb, sizeof(*info)); @@ -1336,13 +1374,13 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, if (skb->len < sizeof(*info)) return SMP_INVALID_PARAMS; - /* Ignore this PDU if it wasn't requested */ - if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - return 0; - /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_ID_KEY; + SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO); + if (smp->remote_key_dist & SMP_DIST_SIGN) + SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO); + skb_pull(skb, sizeof(*info)); hci_dev_lock(hcon->hdev); @@ -1392,13 +1430,11 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - /* Ignore this PDU if it wasn't requested */ - if (!(smp->remote_key_dist & SMP_DIST_SIGN)) - return 0; - /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_SIGN; + SMP_DISALLOW_CMD(smp, SMP_CMD_SIGN_INFO); + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -1418,6 +1454,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) { struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; + struct smp_chan *smp; __u8 code, reason; int err = 0; @@ -1437,18 +1474,19 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) code = skb->data[0]; skb_pull(skb, sizeof(code)); - /* - * The SMP context must be initialized for all other PDUs except - * pairing and security requests. If we get any other PDU when - * not initialized simply disconnect (done if this function - * returns an error). + smp = chan->data; + + if (code > SMP_CMD_MAX) + goto drop; + + if (smp && !test_bit(code, &smp->allow_cmd)) + goto drop; + + /* If we don't have a context the only allowed commands are + * pairing request and security request. */ - if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && - !chan->data) { - BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); - err = -EOPNOTSUPP; - goto done; - } + if (!smp && code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ) + goto drop; switch (code) { case SMP_CMD_PAIRING_REQ: @@ -1510,6 +1548,12 @@ done: } return err; + +drop: + BT_ERR("%s unexpected SMP command 0x%02x from %pMR", hcon->hdev->name, + code, &hcon->dst); + kfree_skb(skb); + return 0; } static void smp_teardown_cb(struct l2cap_chan *chan, int err) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index cf10946..5240537 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -102,6 +102,8 @@ struct smp_cmd_security_req { __u8 auth_req; } __packed; +#define SMP_CMD_MAX 0x0b + #define SMP_PASSKEY_ENTRY_FAILED 0x01 #define SMP_OOB_NOT_AVAIL 0x02 #define SMP_AUTH_REQUIREMENTS 0x03 -- cgit v0.10.2 From 9f06a8d623b2c3aea09292b844e329fbfb401231 Mon Sep 17 00:00:00 2001 From: Behan Webster Date: Fri, 5 Sep 2014 16:03:34 -0700 Subject: Bluetooth: LLVMLinux: Remove VLAIS from bluetooth/amp.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the use of a Variable Length Array In Struct (VLAIS) with a C99 compliant equivalent. This patch allocates the appropriate amount of memory using an char array. The new code can be compiled with both gcc and clang. struct shash_desc contains a flexible array member member ctx declared with CRYPTO_MINALIGN_ATTR, so sizeof(struct shash_desc) aligns the beginning of the array declared after struct shash_desc with long long. No trailing padding is required because it is not a struct type that can be used in an array. The CRYPTO_MINALIGN_ATTR is required so that desc is aligned with long long as would be the case for a struct containing a member with CRYPTO_MINALIGN_ATTR. Signed-off-by: Behan Webster Signed-off-by: Mark Charlebois Signed-off-by: Jan-Simon Möller Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 016cdb6..2640d78 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -149,15 +149,14 @@ static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) if (ret) { BT_DBG("crypto_ahash_setkey failed: err %d", ret); } else { - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(tfm)]; - } desc; + char desc[sizeof(struct shash_desc) + + crypto_shash_descsize(tfm)] CRYPTO_MINALIGN_ATTR; + struct shash_desc *shash = (struct shash_desc *)desc; - desc.shash.tfm = tfm; - desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + shash->tfm = tfm; + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - ret = crypto_shash_digest(&desc.shash, plaintext, psize, + ret = crypto_shash_digest(shash, plaintext, psize, output); } -- cgit v0.10.2 From c68b7f127d5f517c214e8bcf231d0188f6776d2a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 6 Sep 2014 06:59:10 +0300 Subject: Bluetooth: Fix dereferencing conn variable before NULL check This patch fixes the following type of static analyzer warning (and probably a real bug as well as the NULL check should be there for a reason): net/bluetooth/smp.c:1182 smp_conn_security() warn: variable dereferenced before check 'conn' (see line 1174) Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1201670..560f78a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1210,7 +1210,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) { struct l2cap_conn *conn = hcon->l2cap_data; - struct l2cap_chan *chan = conn->smp; + struct l2cap_chan *chan; struct smp_chan *smp; __u8 authreq; int ret; @@ -1221,6 +1221,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (!conn) return 1; + chan = conn->smp; + if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) return 1; -- cgit v0.10.2 From e1e930f591bfd9604c3077f0af5c390f4f890259 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 8 Sep 2014 17:09:49 -0700 Subject: Bluetooth: Fix mgmt pairing failure when authentication fails Whether through HCI with BR/EDR or SMP with LE when authentication fails we should also notify any pending Pair Device mgmt command. This patch updates the mgmt_auth_failed function to take the actual hci_conn object and makes sure that any pending pairing command is notified and cleaned up appropriately. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 045d913..206b92b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1342,8 +1342,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u32 passkey, u8 entered); -void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status); +void mgmt_auth_failed(struct hci_conn *conn, u8 status); void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e6a496a..3a8381a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2320,8 +2320,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->sec_level = conn->pending_sec_level; } } else { - mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + mgmt_auth_failed(conn, ev->status); } clear_bit(HCI_CONN_AUTH_PEND, &conn->flags); @@ -3900,8 +3899,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, * event gets always produced as initiator and is also mapped to * the mgmt_auth_failed event */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status) - mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type, - ev->status); + mgmt_auth_failed(conn, ev->status); hci_conn_drop(conn); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ab9521a..efb71b0 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6485,16 +6485,23 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr, return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL); } -void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, - u8 addr_type, u8 status) +void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status) { struct mgmt_ev_auth_failed ev; + struct pending_cmd *cmd; + u8 status = mgmt_status(hci_status); - bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_bdaddr(link_type, addr_type); - ev.status = mgmt_status(status); + bacpy(&ev.addr.bdaddr, &conn->dst); + ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type); + ev.status = status; - mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); + cmd = find_pairing(conn); + + mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); + + if (cmd) + pairing_complete(cmd, status); } void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 560f78a..25c9040 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -420,8 +420,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) &reason); clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags); - mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, - HCI_ERROR_AUTH_FAILURE); + mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE); if (chan->data) smp_chan_destroy(conn); -- cgit v0.10.2 From 85560c4a828ec9c8573840c9b66487b6ae584768 Mon Sep 17 00:00:00 2001 From: Champion Chen Date: Sat, 6 Sep 2014 14:06:08 -0500 Subject: Bluetooth: Fix issue with USB suspend in btusb driver Suspend could fail for some platforms because btusb_suspend==> btusb_stop_traffic ==> usb_kill_anchored_urbs. When btusb_bulk_complete returns before system suspend and resubmits an URB, the system cannot enter suspend state. Signed-off-by: Champion Chen Signed-off-by: Larry Finger Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 0527b29..a79d657 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -331,6 +331,9 @@ static void btusb_intr_complete(struct urb *urb) BT_ERR("%s corrupted event packet", hdev->name); hdev->stat.err_rx++; } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_INTR_RUNNING, &data->flags)) @@ -419,6 +422,9 @@ static void btusb_bulk_complete(struct urb *urb) BT_ERR("%s corrupted ACL packet", hdev->name); hdev->stat.err_rx++; } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_BULK_RUNNING, &data->flags)) @@ -513,6 +519,9 @@ static void btusb_isoc_complete(struct urb *urb) hdev->stat.err_rx++; } } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; } if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags)) -- cgit v0.10.2 From 2ae50d8d3aaf7154f72b44331b71f15799cdc1bb Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 8 Sep 2014 12:11:43 +0300 Subject: Bluetooth: 6lowpan: Increase the connection timeout value Use the default connection timeout value defined in l2cap.h because the current timeout was too short and most of the time the connection attempts timed out. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.17.x diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 35ebe79..5532e6e 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -890,7 +890,7 @@ static void chan_resume_cb(struct l2cap_chan *chan) static long chan_get_sndtimeo_cb(struct l2cap_chan *chan) { - return msecs_to_jiffies(1000); + return L2CAP_CONN_TIMEOUT; } static const struct l2cap_ops bt_6lowpan_chan_ops = { -- cgit v0.10.2 From b2799cec22812f5f1aaaa57133df51876f685d84 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 8 Sep 2014 12:11:44 +0300 Subject: Bluetooth: 6lowpan: Set the peer IPv6 address correctly The peer IPv6 address contained wrong U/L bit in the EUI-64 part. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.17.x diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 5532e6e..b229aed 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -671,6 +671,14 @@ static struct l2cap_chan *chan_open(struct l2cap_chan *pchan) return chan; } +static void set_ip_addr_bits(u8 addr_type, u8 *addr) +{ + if (addr_type == BDADDR_LE_PUBLIC) + *addr |= 0x02; + else + *addr &= ~0x02; +} + static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, struct lowpan_dev *dev) { @@ -693,6 +701,11 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, EUI64_ADDR_LEN); + /* IPv6 address needs to have the U/L bit set properly so toggle + * it back here. + */ + set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8); + write_lock_irqsave(&devices_lock, flags); INIT_LIST_HEAD(&peer->list); peer_add(dev, peer); -- cgit v0.10.2 From 39e90c77637b3892a39f2908aea57539e961c50e Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 8 Sep 2014 12:11:45 +0300 Subject: Bluetooth: 6lowpan: Route packets that are not meant to peer via correct device Packets that are supposed to be delivered via the peer device need to be checked and sent to correct device. This requires that user has set the routes properly so that the 6lowpan module can then figure out the destination gateway and the correct Bluetooth device. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.17.x diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index b229aed..0920cb6 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -39,6 +39,7 @@ static struct dentry *lowpan_control_debugfs; struct skb_cb { struct in6_addr addr; + struct in6_addr gw; struct l2cap_chan *chan; int status; }; @@ -158,6 +159,54 @@ static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, return NULL; } +static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, + struct in6_addr *daddr, + struct sk_buff *skb) +{ + struct lowpan_peer *peer, *tmp; + struct in6_addr *nexthop; + struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); + int count = atomic_read(&dev->peer_count); + + BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt); + + /* If we have multiple 6lowpan peers, then check where we should + * send the packet. If only one peer exists, then we can send the + * packet right away. + */ + if (count == 1) + return list_first_entry(&dev->peers, struct lowpan_peer, + list); + + if (!rt) { + nexthop = &lowpan_cb(skb)->gw; + + if (ipv6_addr_any(nexthop)) + return NULL; + } else { + nexthop = rt6_nexthop(rt); + + /* We need to remember the address because it is needed + * by bt_xmit() when sending the packet. In bt_xmit(), the + * destination routing info is not set. + */ + memcpy(&lowpan_cb(skb)->gw, nexthop, sizeof(struct in6_addr)); + } + + BT_DBG("gw %pI6c", nexthop); + + list_for_each_entry_safe(peer, tmp, &dev->peers, list) { + BT_DBG("dst addr %pMR dst type %d ip %pI6c", + &peer->chan->dst, peer->chan->dst_type, + &peer->peer_addr); + + if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) + return peer; + } + + return NULL; +} + static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) { struct lowpan_dev *entry, *tmp; @@ -415,8 +464,18 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, read_unlock_irqrestore(&devices_lock, flags); if (!peer) { - BT_DBG("no such peer %pMR found", &addr); - return -ENOENT; + /* The packet might be sent to 6lowpan interface + * because of routing (either via default route + * or user set route) so get peer according to + * the destination address. + */ + read_lock_irqsave(&devices_lock, flags); + peer = peer_lookup_dst(dev, &hdr->daddr, skb); + read_unlock_irqrestore(&devices_lock, flags); + if (!peer) { + BT_DBG("no such peer %pMR found", &addr); + return -ENOENT; + } } daddr = peer->eui64_addr; @@ -520,6 +579,8 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) read_lock_irqsave(&devices_lock, flags); peer = peer_lookup_ba(dev, &addr, addr_type); + if (!peer) + peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb); read_unlock_irqrestore(&devices_lock, flags); BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", -- cgit v0.10.2 From dc8ecdd3a3fccf73fcb07711cde064ce5727f9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 1 Sep 2014 23:11:06 +0200 Subject: bcma: move bus struct setup into early part of host specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is important for SoC host. In future we will want to know chip ID (needed for early MIPS boot) before doing cores scanning. Signed-off-by: Rafał Miłecki Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index f032ed6..1e5ac0a 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -208,6 +208,9 @@ static int bcma_host_pci_probe(struct pci_dev *dev, bus->boardinfo.vendor = bus->host_pci->subsystem_vendor; bus->boardinfo.type = bus->host_pci->subsystem_device; + /* Initialize struct, detect chip */ + bcma_init_bus(bus); + /* Register */ err = bcma_bus_register(bus); if (err) diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 1edd7e0..379e0d4e 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -178,6 +178,9 @@ int __init bcma_host_soc_register(struct bcma_soc *soc) bus->hosttype = BCMA_HOSTTYPE_SOC; bus->ops = &bcma_host_soc_ops; + /* Initialize struct, detect chip */ + bcma_init_bus(bus); + /* Register */ err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); if (err) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 0ff8d58..9f6b0cb 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -334,8 +334,6 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, struct bcma_device *core; struct bcma_device_id match; - bcma_init_bus(bus); - match.manuf = BCMA_MANUF_BCM; match.id = bcma_cc_core_id(bus); match.class = BCMA_CL_SIM; diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index e9bd772..e2b9903 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -438,9 +438,6 @@ void bcma_init_bus(struct bcma_bus *bus) s32 tmp; struct bcma_chipinfo *chipinfo = &(bus->chipinfo); - if (bus->init_done) - return; - INIT_LIST_HEAD(&bus->cores); bus->nr_cores = 0; @@ -452,8 +449,6 @@ void bcma_init_bus(struct bcma_bus *bus) chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", chipinfo->id, chipinfo->rev, chipinfo->pkg); - - bus->init_done = true; } int bcma_bus_scan(struct bcma_bus *bus) @@ -463,8 +458,6 @@ int bcma_bus_scan(struct bcma_bus *bus) int err, core_num = 0; - bcma_init_bus(bus); - erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); if (bus->hosttype == BCMA_HOSTTYPE_SOC) { eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 0272e49..c1ba87d 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -332,7 +332,6 @@ struct bcma_bus { struct bcma_device *mapped_core; struct list_head cores; u8 nr_cores; - u8 init_done:1; u8 num; struct bcma_drv_cc drv_cc; -- cgit v0.10.2 From a395135ddebb0a06052b84c309eb6cb68b79c797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 1 Sep 2014 23:11:07 +0200 Subject: bcma: use separated function to initialize bus on SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to split SoC bus init into two phases. The later one (which includes scanning) should be called when kalloc is available. Cc: Ralf Baechle Signed-off-by: Rafał Miłecki Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 2b63e7e..fff6ed4 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -202,6 +202,10 @@ static void __init bcm47xx_register_bcma(void) err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) + panic("Failed to register BCMA bus (err %d)", err); + + err = bcma_host_soc_init(&bcm47xx_bus.bcma); + if (err) panic("Failed to initialize BCMA bus (err %d)", err); bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL); diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 379e0d4e..718e054 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -165,7 +165,6 @@ static const struct bcma_host_ops bcma_host_soc_ops = { int __init bcma_host_soc_register(struct bcma_soc *soc) { struct bcma_bus *bus = &soc->bus; - int err; /* iomap only first core. We have to read some register on this core * to scan the bus. @@ -181,7 +180,15 @@ int __init bcma_host_soc_register(struct bcma_soc *soc) /* Initialize struct, detect chip */ bcma_init_bus(bus); - /* Register */ + return 0; +} + +int __init bcma_host_soc_init(struct bcma_soc *soc) +{ + struct bcma_bus *bus = &soc->bus; + int err; + + /* Scan bus and initialize it */ err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); if (err) iounmap(bus->mmio); diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h index 4203c55..f24d245 100644 --- a/include/linux/bcma/bcma_soc.h +++ b/include/linux/bcma/bcma_soc.h @@ -10,6 +10,7 @@ struct bcma_soc { }; int __init bcma_host_soc_register(struct bcma_soc *soc); +int __init bcma_host_soc_init(struct bcma_soc *soc); int bcma_bus_register(struct bcma_bus *bus); -- cgit v0.10.2 From e79fff28587c9437282c863722d1fa186143f62a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:40 -0500 Subject: rtlwifi: btcoexist: Modify btcoexist for changes in the V062814 Realtek version This patch is the first of a set to bring this driver up to the latest Realtek code. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c index d916ab9..bd37d65 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -49,8 +49,8 @@ static const char *const glbt_info_src_8723b_2ant[] = { "BT Info[bt auto report]", }; -static u32 glcoex_ver_date_8723b_2ant = 20130731; -static u32 glcoex_ver_8723b_2ant = 0x3b; +static u32 glcoex_ver_date_8723b_2ant = 20131113; +static u32 glcoex_ver_8723b_2ant = 0x3f; /************************************************************** * local function proto type if needed @@ -303,6 +303,21 @@ static void btc8723b2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); } +static void btc8723b2ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) { static bool pre_wifi_busy; @@ -604,7 +619,7 @@ static bool btc8723b_need_dec_pwr(struct btc_coexist *btcoexist) if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) return false; - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); if (wifi_connected) { if (bt_hs_on) { @@ -824,7 +839,6 @@ static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex, btc8723b2ant_set_dac_swing_reg(btcoex, 0x18); } - static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist, bool force_exec, bool dac_swing_on, u32 dac_swing_lvl) @@ -884,7 +898,6 @@ static void btc8723b2ant_set_agc_table(struct btc_coexist *btcoexist, btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); } - /* RF Gain */ btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); if (agc_table_en) { @@ -1160,8 +1173,87 @@ static void btc8723b2ant_sw_mechanism2(struct btc_coexist *btcoexist, dac_swing_lvl); } +static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist, + u8 antpos_type, bool init_hwcfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp = 0; + bool pg_ext_switch = false; + bool use_ext_switch = false; + u8 h2c_parameter[2] = {0}; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + + if ((fw_ver < 0xc0000) || pg_ext_switch) + 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(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + /* Force GNT_BT to low */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + + 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); + } else { + /* tell firmware "antenna inverse" */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* ext switch setting */ + if (use_ext_switch) { + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + switch (antpos_type) { + case BTC_ANT_WIFI_AT_MAIN: + /* ext switch main at wifi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x1); + break; + case BTC_ANT_WIFI_AT_AUX: + /* ext switch aux at wifi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, 0x2); + break; + } + } else { /* internal switch */ + /* fixed ext switch */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); + switch (antpos_type) { + case BTC_ANT_WIFI_AT_MAIN: + /* fixed internal switch S1->WiFi, S0->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + break; + case BTC_ANT_WIFI_AT_AUX: + /* fixed internal switch S0->WiFi, S1->BT */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + break; + } + } +} + static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec, - bool turn_on, u8 type) + bool turn_on, u8 type) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, "[BTCoex], %s turn %s PS TDMA, type=%d\n", @@ -1351,7 +1443,8 @@ static void btc8723b2ant_action_bt_inquiry(struct btc_coexist *btcoexist) coex_dm->need_recover_0x948 = true; coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948); - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX, + false, false); } static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist) @@ -1520,7 +1613,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause, btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); coex_dm->tdma_adj_type = 8; - } else if (coex_dm->cur_ps_tdma == 9) { + } + + if (coex_dm->cur_ps_tdma == 9) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); coex_dm->tdma_adj_type = 13; @@ -1607,7 +1702,9 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause, } else if (coex_dm->cur_ps_tdma == 8) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); coex_dm->tdma_adj_type = 4; - } else if (coex_dm->cur_ps_tdma == 13) { + } + + if (coex_dm->cur_ps_tdma == 13) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); coex_dm->tdma_adj_type = 9; } else if (coex_dm->cur_ps_tdma == 14) { @@ -1652,23 +1749,34 @@ static void set_tdma_int1(struct btc_coexist *btcoexist, bool tx_pause, coex_dm->tdma_adj_type = 12; } } else if (result == 1) { - int tmp = coex_dm->cur_ps_tdma; - switch (tmp) { - case 4: - case 3: - case 2: - case 12: - case 11: - case 10: - btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, - true, tmp - 1); - coex_dm->tdma_adj_type = tmp - 1; - break; - case 1: + if (coex_dm->cur_ps_tdma == 4) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 71); coex_dm->tdma_adj_type = 71; - break; + } else if (coex_dm->cur_ps_tdma == 12) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; } } } @@ -1694,7 +1802,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause, } else if (coex_dm->cur_ps_tdma == 4) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); coex_dm->tdma_adj_type = 8; - } else if (coex_dm->cur_ps_tdma == 9) { + } + if (coex_dm->cur_ps_tdma == 9) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); coex_dm->tdma_adj_type = 14; } else if (coex_dm->cur_ps_tdma == 10) { @@ -1776,7 +1885,8 @@ static void set_tdma_int2(struct btc_coexist *btcoexist, bool tx_pause, } else if (coex_dm->cur_ps_tdma == 8) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); coex_dm->tdma_adj_type = 4; - } else if (coex_dm->cur_ps_tdma == 13) { + } + if (coex_dm->cur_ps_tdma == 13) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); coex_dm->tdma_adj_type = 10; } else if (coex_dm->cur_ps_tdma == 14) { @@ -1865,7 +1975,8 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause, } else if (coex_dm->cur_ps_tdma == 4) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); coex_dm->tdma_adj_type = 8; - } else if (coex_dm->cur_ps_tdma == 9) { + } + if (coex_dm->cur_ps_tdma == 9) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); coex_dm->tdma_adj_type = 15; } else if (coex_dm->cur_ps_tdma == 10) { @@ -1935,101 +2046,80 @@ static void set_tdma_int3(struct btc_coexist *btcoexist, bool tx_pause, BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], TxPause = 0\n"); - switch (coex_dm->cur_ps_tdma) { - case 5: + if (coex_dm->cur_ps_tdma == 5) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 6: + } else if (coex_dm->cur_ps_tdma == 6) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 7: + } else if (coex_dm->cur_ps_tdma == 7) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 8: + } else if (coex_dm->cur_ps_tdma == 8) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); coex_dm->tdma_adj_type = 4; - break; - case 13: + } + if (coex_dm->cur_ps_tdma == 13) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 14: + } else if (coex_dm->cur_ps_tdma == 14) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 15: + } else if (coex_dm->cur_ps_tdma == 15) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 16: + } else if (coex_dm->cur_ps_tdma == 16) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); coex_dm->tdma_adj_type = 12; - break; } if (result == -1) { - switch (coex_dm->cur_ps_tdma) { - case 1: + if (coex_dm->cur_ps_tdma == 1) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 2: + } else if (coex_dm->cur_ps_tdma == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 3: + } else if (coex_dm->cur_ps_tdma == 3) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); coex_dm->tdma_adj_type = 4; - break; - case 9: + } else if (coex_dm->cur_ps_tdma == 9) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 10: + } else if (coex_dm->cur_ps_tdma == 10) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 11: + } else if (coex_dm->cur_ps_tdma == 11) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12); coex_dm->tdma_adj_type = 12; - break; } } else if (result == 1) { - switch (coex_dm->cur_ps_tdma) { - case 4: + if (coex_dm->cur_ps_tdma == 4) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 3: + } else if (coex_dm->cur_ps_tdma == 3) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 2: + } else if (coex_dm->cur_ps_tdma == 2) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); coex_dm->tdma_adj_type = 3; - break; - case 12: + } else if (coex_dm->cur_ps_tdma == 12) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 11: + } else if (coex_dm->cur_ps_tdma == 11) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; - break; - case 10: + } else if (coex_dm->cur_ps_tdma == 10) { btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); coex_dm->tdma_adj_type = 11; @@ -2328,7 +2418,7 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2385,12 +2475,43 @@ static void btc8723b2ant_action_hid(struct btc_coexist *btcoexist) /*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/ static void btc8723b2ant_action_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; wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist, + 1, 2, 40, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + /* driver don't know AP num in Linux, so we will never enter this if */ + if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) { + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0); + btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + btc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } else { + btc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + btc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } + return; + } btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2501,7 +2622,7 @@ static void btc8723b2ant_action_pan_edr(struct btc_coexist *btcoexist) wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2612,7 +2733,7 @@ static void btc8723b2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2676,7 +2797,7 @@ static void btc8723b2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); if (btc8723b_need_dec_pwr(btcoexist)) @@ -2746,7 +2867,7 @@ static void btc8723b2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2809,8 +2930,8 @@ static void btc8723b2ant_action_hid_a2dp(struct btc_coexist *btcoexist) u32 wifi_bw; wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist, - 0, 2, 15, 0); - bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0); + 0, 2, 15, 0); + bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0); btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); @@ -2982,7 +3103,15 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) } } - +static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist) +{ + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + /* Force GNT_BT to High */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + /* BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); +} /********************************************************************* * work around function start with wa_btc8723b2ant_ @@ -2990,98 +3119,24 @@ static void btc8723b2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) /********************************************************************* * extern function start with EXbtc8723b2ant_ *********************************************************************/ -void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) +void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) { - struct btc_board_info *board_info = &btcoexist->board_info; - u32 u32tmp = 0, fw_ver; u8 u8tmp = 0; - u8 h2c_parameter[2] = {0}; - BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, "[BTCoex], 2Ant Init HW Config!!\n"); + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); - /* backup rf 0x1e value */ - coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist, - BTC_RF_A, 0x1e, - 0xfffff); - - /* 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(btcoexist, 0x974, 0xff); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); - btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); - - /* Antenna switch control parameter */ - /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/ - - /*Force GNT_BT to low*/ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); - btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); - - /* 0x790[5:0]=0x5 */ + /* 0x790[5:0] = 0x5 */ u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); u8tmp &= 0xc0; u8tmp |= 0x5; btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); - - /*Antenna config */ - btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); - - /*ext switch for fw ver < 0xc */ - if (fw_ver < 0xc00) { - if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x1); - /*Main Ant to BT for IPS case 0x4c[23]=1*/ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, - 0x1); - - /*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); - } else { - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, - 0x3, 0x2); - /*Aux Ant to BT for IPS case 0x4c[23]=1*/ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, - 0x0); - - /*tell firmware "antenna inverse"*/ - h2c_parameter[0] = 1; - h2c_parameter[1] = 1; /*ext switch type*/ - btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, - h2c_parameter); - } - } else { - /*ext switch always at s1 (if exist) */ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1); - /*Main Ant to BT for IPS case 0x4c[23]=1*/ - btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1); - - if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { - /*tell firmware "no antenna inverse"*/ - h2c_parameter[0] = 0; - h2c_parameter[1] = 0; /*ext switch type*/ - btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, - h2c_parameter); - } else { - /*tell firmware "antenna inverse"*/ - h2c_parameter[0] = 1; - h2c_parameter[1] = 0; /*ext switch type*/ - btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, - h2c_parameter); - } - } - + /*Antenna config */ + btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, + true, false); /* PTA parameter */ btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0); @@ -3092,14 +3147,14 @@ void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist) btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); } -void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) +void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, "[BTCoex], Coex Mechanism Init!!\n"); btc8723b2ant_init_coex_dm(btcoexist); } -void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) +void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; @@ -3114,6 +3169,7 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck; u8 wifi_dot11_chnl, wifi_hs_chnl; u32 fw_ver = 0, bt_patch_ver = 0; + u8 ap_num = 0; CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); @@ -3171,8 +3227,9 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", - "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num); CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); @@ -3301,7 +3358,6 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3); CL_PRINTF(cli_buf); - u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); @@ -3371,22 +3427,26 @@ void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) BTC_DBG_DISP_COEX_STATISTICS); } - -void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) { if (BTC_IPS_ENTER == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], IPS ENTER notify\n"); coex_sta->under_ips = true; + btc8723b2ant_wifioff_hwcfg(btcoexist); + btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); btc8723b2ant_coex_alloff(btcoexist); } else if (BTC_IPS_LEAVE == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], IPS LEAVE notify\n"); coex_sta->under_ips = false; + ex_btc8723b2ant_init_hwconfig(btcoexist); + btc8723b2ant_init_coex_dm(btcoexist); + btc8723b2ant_query_bt_info(btcoexist); } } -void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) { if (BTC_LPS_ENABLE == type) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, @@ -3399,7 +3459,7 @@ void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) } } -void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) { if (BTC_SCAN_START == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, @@ -3409,7 +3469,7 @@ void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], SCAN FINISH notify\n"); } -void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) { if (BTC_ASSOCIATE_START == type) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, @@ -3419,8 +3479,8 @@ void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) "[BTCoex], CONNECT FINISH notify\n"); } -void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) { u8 h2c_parameter[3] = {0}; u32 wifi_bw; @@ -3460,16 +3520,16 @@ void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); } -void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type) +void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) { if (type == BTC_PACKET_DHCP) BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], DHCP Packet notify\n"); } -void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length) +void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length) { u8 bt_info = 0; u8 i, rsp_source = 0; @@ -3516,7 +3576,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->bt_info_c2h[rsp_source][4]; /* Here we need to resend some wifi info to BT - * because bt is reset and loss of the info. + because bt is reset and loss of the info. */ if ((coex_sta->bt_info_ext & BIT1)) { BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, @@ -3525,11 +3585,13 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); if (wifi_connected) - btc8723b_med_stat_notify(btcoexist, - BTC_MEDIA_CONNECT); + ex_btc8723b2ant_media_status_notify( + btcoexist, + BTC_MEDIA_CONNECT); else - btc8723b_med_stat_notify(btcoexist, - BTC_MEDIA_DISCONNECT); + ex_btc8723b2ant_media_status_notify( + btcoexist, + BTC_MEDIA_DISCONNECT); } if ((coex_sta->bt_info_ext & BIT3)) { @@ -3564,7 +3626,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_sta->a2dp_exist = false; coex_sta->hid_exist = false; coex_sta->sco_exist = false; - } else { /* connection exists */ + } else { /* connection exists */ coex_sta->bt_link_exist = true; if (bt_info & BT_INFO_8723B_2ANT_B_FTP) coex_sta->pan_exist = true; @@ -3601,7 +3663,7 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); - } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) { + } else if (bt_info&BT_INFO_8723B_2ANT_B_ACL_BUSY) { coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); @@ -3630,26 +3692,16 @@ void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, btc8723b2ant_run_coexist_mechanism(btcoexist); } -void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist, - u8 type) -{ - if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type) - BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, - "[BTCoex],StackOP Inquiry/page/pair start notify\n"); - else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) - BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, - "[BTCoex],StackOP Inquiry/page/pair finish notify\n"); -} - -void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist) +void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist) { BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + btc8723b2ant_wifioff_hwcfg(btcoexist); btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); - btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT); + ex_btc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); } -void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist) +void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; @@ -3677,8 +3729,7 @@ void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist) &bt_patch_ver); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, - "[BTCoex], CoexVer/ FwVer/ PatchVer = " - "%d_%x/ 0x%x/ 0x%x(%d)\n", + "[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); BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h index e0ad8e5..567f354 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h @@ -153,21 +153,20 @@ struct coex_sta_8723b_2ant { /********************************************************************* * The following is interface which will notify coex module. *********************************************************************/ -void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist); -void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist); -void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); -void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type); -void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, - u8 *tmpbuf, u8 length); -void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist, - u8 type); -void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist); -void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist); -void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist); +void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist); #endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index d4bd550..9b9d09a 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -672,7 +672,7 @@ void exhalbtc_init_hw_config(struct btc_coexist *btcoexist) btcoexist->statistics.cnt_init_hw_config++; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_init_hwconfig(btcoexist); + ex_btc8723b2ant_init_hwconfig(btcoexist); } void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) @@ -686,7 +686,7 @@ void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist) btcoexist->statistics.cnt_init_coex_dm++; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_init_coex_dm(btcoexist); + ex_btc8723b2ant_init_coex_dm(btcoexist); btcoexist->initilized = true; } @@ -711,7 +711,7 @@ void exhalbtc_ips_notify(struct btc_coexist *btcoexist, u8 type) halbtc_leave_low_power(); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type); + ex_btc8723b2ant_ips_notify(btcoexist, ips_type); halbtc_nomal_low_power(); } @@ -734,7 +734,7 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type) lps_type = BTC_LPS_ENABLE; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type); + ex_btc8723b2ant_lps_notify(btcoexist, lps_type); } void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) @@ -757,7 +757,7 @@ void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type) halbtc_leave_low_power(); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type); + ex_btc8723b2ant_scan_notify(btcoexist, scan_type); halbtc_nomal_low_power(); } @@ -782,7 +782,7 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) halbtc_leave_low_power(); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type); + ex_btc8723b2ant_connect_notify(btcoexist, asso_type); } void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, @@ -805,9 +805,6 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, halbtc_leave_low_power(); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - btc8723b_med_stat_notify(btcoexist, status); - halbtc_nomal_low_power(); } @@ -828,8 +825,8 @@ void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type) halbtc_leave_low_power(); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_special_packet_notify(btcoexist, - packet_type); + ex_btc8723b2ant_special_packet_notify(btcoexist, + packet_type); halbtc_nomal_low_power(); } @@ -844,7 +841,7 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, btcoexist->statistics.cnt_bt_info_notify++; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); + ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length); } void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) @@ -863,10 +860,6 @@ void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) halbtc_leave_low_power(); - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_stack_operation_notify(btcoexist, - stack_op_type); - halbtc_nomal_low_power(); } @@ -878,7 +871,7 @@ void exhalbtc_halt_notify(struct btc_coexist *btcoexist) return; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_halt_notify(btcoexist); + ex_btc8723b2ant_halt_notify(btcoexist); } void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) @@ -898,7 +891,7 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist) halbtc_leave_low_power(); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_periodical(btcoexist); + ex_btc8723b2ant_periodical(btcoexist); halbtc_nomal_low_power(); } @@ -997,5 +990,5 @@ void exhalbtc_display_bt_coex_info(struct btc_coexist *btcoexist) return; if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) - ex_halbtc8723b2ant_display_coex_info(btcoexist); + ex_btc8723b2ant_display_coex_info(btcoexist); } diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index 049f4c8..e90af4b 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -55,6 +55,17 @@ #define BTC_RATE_DISABLE 0 #define BTC_RATE_ENABLE 1 +/* single Antenna definition */ +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 +/* dual Antenna definition */ +#define BTC_ANT_WIFI_AT_MAIN 0 +#define BTC_ANT_WIFI_AT_AUX 1 +/* coupler Antenna definition */ +#define BTC_ANT_WIFI_AT_CPL_MAIN 0 +#define BTC_ANT_WIFI_AT_CPL_AUX 1 + #define BTC_ANT_PATH_WIFI 0 #define BTC_ANT_PATH_BT 1 #define BTC_ANT_PATH_PTA 2 @@ -164,6 +175,16 @@ extern u32 btc_dbg_type[]; #define BTC_ANT_PATH_BT 1 #define BTC_ANT_PATH_PTA 2 +#define BTC_RSSI_HIGH(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_HIGH || \ + _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false) +#define BTC_RSSI_MEDIUM(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_MEDIUM || \ + _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false) +#define BTC_RSSI_LOW(_rssi_) \ + ((_rssi_ == BTC_RSSI_STATE_LOW || \ + _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false) + enum btc_power_save_type { BTC_PS_WIFI_NATIVE = 0, BTC_PS_LPS_ON = 1, @@ -260,6 +281,7 @@ enum btc_get_type { BTC_GET_U1_WIFI_CENTRAL_CHNL, BTC_GET_U1_WIFI_HS_CHNL, BTC_GET_U1_MAC_PHY_MODE, + BTC_GET_U1_AP_NUM, /* for 1Ant */ BTC_GET_U1_LPS_MODE, -- cgit v0.10.2 From e8f3fef412d4ffd8cb1bd5cd7a6e5572e21bf80a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:41 -0500 Subject: rtlwifi: btcoexist: Modify rtl_btc for changes in latest Realtek code Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c index 0ab94fe..826b1a6 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c @@ -22,19 +22,19 @@ * Larry Finger * *****************************************************************************/ - #include "../wifi.h" -#include "rtl_btc.h" -#include "halbt_precomp.h" - #include #include +#include "rtl_btc.h" +#include "halbt_precomp.h" + static struct rtl_btc_ops rtl_btc_operation = { .btc_init_variables = rtl_btc_init_variables, .btc_init_hal_vars = rtl_btc_init_hal_vars, .btc_init_hw_config = rtl_btc_init_hw_config, .btc_ips_notify = rtl_btc_ips_notify, + .btc_lps_notify = rtl_btc_lps_notify, .btc_scan_notify = rtl_btc_scan_notify, .btc_connect_notify = rtl_btc_connect_notify, .btc_mediastatus_notify = rtl_btc_mediastatus_notify, @@ -44,6 +44,7 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_is_limited_dig = rtl_btc_is_limited_dig, .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, .btc_is_bt_disabled = rtl_btc_is_bt_disabled, + .btc_special_packet_notify = rtl_btc_special_packet_notify, }; void rtl_btc_init_variables(struct rtl_priv *rtlpriv) @@ -85,6 +86,11 @@ void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type) exhalbtc_ips_notify(&gl_bt_coexist, type); } +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type) +{ + exhalbtc_lps_notify(&gl_bt_coexist, type); +} + void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype) { exhalbtc_scan_notify(&gl_bt_coexist, scantype); @@ -103,6 +109,7 @@ void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, void rtl_btc_periodical(struct rtl_priv *rtlpriv) { + /*rtl_bt_dm_monitor();*/ exhalbtc_periodical(&gl_bt_coexist); } @@ -150,12 +157,18 @@ bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv) bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv) { + /* It seems 'bt_disabled' is never be initialized or set. */ if (gl_bt_coexist.bt_info.bt_disabled) return true; else return false; } +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type) +{ + return exhalbtc_special_packet_notify(&gl_bt_coexist, pkt_type); +} + struct rtl_btc_ops *rtl_btc_get_ops_pointer(void) { return &rtl_btc_operation; diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h index 805b22c..d5218ce 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h @@ -31,6 +31,7 @@ void rtl_btc_init_variables(struct rtl_priv *rtlpriv); void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv); void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv); void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type); +void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type); void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, @@ -41,6 +42,7 @@ void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); +void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type); struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 407a793..e44e2df 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -2312,6 +2312,7 @@ struct rtl_btc_ops { void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv); void (*btc_init_hw_config) (struct rtl_priv *rtlpriv); void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type); + void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type); void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype); void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action); void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv, @@ -2323,6 +2324,8 @@ struct rtl_btc_ops { bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv); bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv); bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); + void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv, + u8 pkt_type); }; struct proxim { -- cgit v0.10.2 From 2187e9a2ce575ee85a1ce31fa2ecbc0f580c105f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:42 -0500 Subject: rtlwifi: btcoexist: Modify driver for V062814 Realtek driver This patch adds the routines needed to support BT coexistence with the new rtl8192ee driver. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c new file mode 100644 index 0000000..af3f604 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -0,0 +1,3888 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +/************************************************************** + * Description: + * + * This file is for RTL8192E Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + **************************************************************/ + +/************************************************************** + * include files + **************************************************************/ +#include "halbt_precomp.h" +/************************************************************** + * Global variables, these are static variables + **************************************************************/ +static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant; +static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant; +static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant; +static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant; + +static const char *const GLBtInfoSrc8192e2Ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8192e_2ant = 20130902; +static u32 glcoex_ver_8192e_2ant = 0x34; + +/************************************************************** + * local function proto type if needed + **************************************************************/ +/************************************************************** + * local function start with halbtc8192e2ant_ + **************************************************************/ +static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + int btrssi = 0; + u8 btrssi_state = coex_sta->pre_bt_rssi_state; + + btrssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state = LOW\n"); + if (btrssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to High\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Low\n"); + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state = HIGH\n"); + if (btrssi < rssi_thresh) { + btrssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Low\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state = LOW\n"); + if (btrssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Medium\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi pre state = MEDIUM\n"); + if (btrssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + btrssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to High\n"); + } else if (btrssi < rssi_thresh) { + btrssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Low\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at Medium\n"); + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi pre state = HIGH\n"); + if (btrssi < rssi_thresh1) { + btrssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state switch to Medium\n"); + } else { + btrssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "BT Rssi state stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = btrssi_state; + + return btrssi_state; +} + +static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + int wifirssi = 0; + u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifirssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to High\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Low\n"); + } + } else { + if (wifirssi < rssi_thresh) { + wifirssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Low\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifirssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Medium\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifirssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) { + wifirssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to High\n"); + } else if (wifirssi < rssi_thresh) { + wifirssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Low\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at Medium\n"); + } + } else { + if (wifirssi < rssi_thresh1) { + wifirssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state switch to Medium\n"); + } else { + wifirssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "wifi RSSI state stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifirssi_state; + + return wifirssi_state; +} + +static void btc8192e2ant_monitor_bt_enable_dis(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters = 0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + } + } + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + pre_bt_disabled = bt_disabled; + } +} + +static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist, + u8 sstype, u32 ra_masktype) +{ + u32 disra_mask = 0x0; + + switch (ra_masktype) { + case 0: /* normal mode */ + if (sstype == 2) + disra_mask = 0x0; /* enable 2ss */ + else + disra_mask = 0xfff00000;/* disable 2ss */ + break; + case 1: /* disable cck 1/2 */ + if (sstype == 2) + disra_mask = 0x00000003;/* enable 2ss */ + else + disra_mask = 0xfff00003;/* disable 2ss */ + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + if (sstype == 2) + disra_mask = 0x0001f1f7;/* enable 2ss */ + else + disra_mask = 0xfff1f1f7;/* disable 2ss */ + break; + default: + break; + } + + return disra_mask; +} + +static void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_ratemask) +{ + coex_dm->curra_mask = dis_ratemask; + + if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, + &coex_dm->curra_mask); + coex_dm->prera_mask = coex_dm->curra_mask; +} + +static void btc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_bmode = false; + + coex_dm->cur_arfrtype = type; + + if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) { + switch (coex_dm->cur_arfrtype) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_bmode); + if (wifi_under_bmode) { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfrtype = coex_dm->cur_arfrtype; +} + +static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retrylimit_type = type; + + if (force_exec || (coex_dm->pre_retrylimit_type != + coex_dm->cur_retrylimit_type)) { + switch (coex_dm->cur_retrylimit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retrylimit); + break; + case 1: /* retry limit = 8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type; +} + +static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdutime_type = type; + + if (force_exec || (coex_dm->pre_ampdutime_type != + coex_dm->cur_ampdutime_type)) { + switch (coex_dm->cur_ampdutime_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_maxtime); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type; +} + +static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_masktype, + u8 arfr_type, u8 retrylimit_type, + u8 ampdutime_type) +{ + u32 disra_mask = 0x0; + + coex_dm->curra_masktype = ra_masktype; + disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, + coex_dm->cur_sstype, + ra_masktype); + halbtc8192e2ant_Updatera_mask(btcoexist, force_exec, disra_mask); +btc8192e2ant_autorate_fallback_retry(btcoexist, force_exec, arfr_type); + halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type); + halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type); +} + +static void halbtc8192e2ant_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, only work + * 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 halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD)>>16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD)>>16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[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); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex] Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hson = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + + 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_hson) { + 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 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + bool bt_hson = false; + u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED; + u8 numdiffprofile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + numdiffprofile++; + if (bt_link_info->hid_exist) + numdiffprofile++; + if (bt_link_info->pan_exist) + numdiffprofile++; + if (bt_link_info->a2dp_exist) + numdiffprofile++; + + if (numdiffprofile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP only\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "PAN(HS) only\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "PAN(EDR) only\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (numdiffprofile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP ==> SCO\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + if (stack_info->num_of_hid >= 2) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID*2 + A2DP\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP + PAN(HS)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (numdiffprofile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO + A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (numdiffprofile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hson) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "ErrorSCO+HID+A2DP+PAN(HS)\n"); + + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "SCO+HID+A2DP+PAN(EDR)\n"); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist, + u8 dac_swinglvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + */ + h2c_parameter[0] = dac_swinglvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swinglvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist, + u8 dec_btpwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_btpwr_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex] decrease Bt Power level = %d, FW write 0x62 = 0x%x\n", + dec_btpwr_lvl, h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist, + bool force_exec, u8 dec_btpwr_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s Dec BT power level = %d\n", + (force_exec ? "force to" : ""), dec_btpwr_lvl); + coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + } + halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist, + bool enable_autoreport) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_autoreport) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", + (enable_autoreport ? "Enabled!!" : "Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_autoreport) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Auto report = %s\n", + (force_exec ? "force to" : ""), + ((enable_autoreport) ? "Enabled" : "Disabled")); + coex_dm->cur_bt_auto_report = enable_autoreport; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex] bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8192e2ant_set_bt_autoreport(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist, + bool force_exec, u8 fw_dac_swinglvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec ? "force to" : ""), fw_dac_swinglvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex] preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8192e2ant_setfw_dac_swinglevel(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void btc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffffc); + } else { + /* Resume RF Rx LPF corner + * After initialized, we can use coex_dm->btRf0x1eBackup + */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec ? "force to" : ""), + ((rx_rf_shrink_on) ? "ON" : "OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex]bPreRfRxLpfShrink=%d,bCurRfRxLpfShrink=%d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + btc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist, + u32 level) +{ + u8 val = (u8)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +static void btc8192e2ant_setsw_full_swing(struct btc_coexist *btcoexist, + bool sw_dac_swingon, + u32 sw_dac_swinglvl) +{ + if (sw_dac_swingon) + halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl); + else + halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18); +} + +static void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swingon, + u32 dac_swinglvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing=%s, dac_swinglvl = 0x%x\n", + (force_exec ? "force to" : ""), + ((dac_swingon) ? "ON" : "OFF"), dac_swinglvl); + coex_dm->cur_dac_swing_on = dac_swingon; + coex_dm->cur_dac_swing_lvl = dac_swinglvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl = 0x%x, ", + coex_dm->pre_dac_swing_on, + coex_dm->pre_dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "bCurDacSwingOn=%d, curDacSwingLvl = 0x%x\n", + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + btc8192e2ant_setsw_full_swing(btcoexist, dac_swingon, dac_swinglvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist, + bool agc_table_en) +{ + /* BB AGC Gain Table */ + if (agc_table_en) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table On!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB Agc Table Off!\n"); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + } +} + +static void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist, + bool force_exec, bool agc_table_en) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s %s Agc Table\n", + (force_exec ? "force to" : ""), + ((agc_table_en) ? "Enable" : "Disable")); + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en); + + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, ", + (force_exec ? "force to" : ""), val0x6c0); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", + val0x6c4, val0x6c8, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, ", + coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n", + coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x,\n", + coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", + coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc); + + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void btc8192e2ant_coex_tbl_w_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 3: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff, + 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff, + 0x5ffb5ffb, 0xffffff, 0x3); + break; + default: + break; + } +} + +static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0; /* function enable */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d ", + coex_dm->pre_ignore_wlan_act); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "bCurIgnoreWlanAct = %d!!\n", + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1, + u8 byte2, u8 byte3, u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void btc8192e2ant_sw_mec1(struct btc_coexist *btcoexist, + bool shrink_rx_lpf, bool low_penalty_ra, + bool limited_dig, bool btlan_constrain) +{ + halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); +} + +static void btc8192e2ant_sw_mec2(struct btc_coexist *btcoexist, + bool agc_table_shift, bool adc_backoff, + bool sw_dac_swing, u32 dac_swinglvl) +{ + halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift); + halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swinglvl); +} + +static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec ? "force to" : ""), + (turn_on ? "ON" : "OFF"), type); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10, + 0x3, 0xf1, 0x90); + break; + case 5: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 7: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); + break; + case 8: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xa3, 0x10, + 0x3, 0x70, 0x90); + break; + case 9: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x10); + break; + case 10: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x10); + break; + case 11: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x10); + break; + case 12: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10, + 0x3, 0xf1, 0x10); + break; + case 13: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe0, 0x10); + break; + case 14: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe0, 0x10); + break; + case 15: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf0, 0x10); + break; + case 16: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12, + 0x3, 0xf0, 0x10); + break; + case 17: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x61, 0x20, + 0x03, 0x10, 0x10); + break; + case 18: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 71: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + default: + case 0: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0, + 0x0, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case 1: + halbtc8192e2ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0, + 0x8, 0x0); + mdelay(5); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist, + u8 sstype) +{ + u8 mimops = BTC_MIMO_PS_DYNAMIC; + u32 disra_mask = 0x0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], REAL set SS Type = %d\n", sstype); + + disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype, + coex_dm->curra_masktype); + halbtc8192e2ant_Updatera_mask(btcoexist, FORCE_EXEC, disra_mask); + + if (sstype == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + /* switch ofdm path */ + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111); + /* switch cck patch */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81); + mimops = BTC_MIMO_PS_STATIC; + } else if (sstype == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0); + btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41); + mimops = BTC_MIMO_PS_DYNAMIC; + } + /* set rx 1ss or 2ss */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops); +} + +static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist, + bool force_exec, u8 new_sstype) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], %s Switch SS Type = %d\n", + (force_exec ? "force to" : ""), new_sstype); + coex_dm->cur_sstype = new_sstype; + + if (!force_exec) { + if (coex_dm->pre_sstype == coex_dm->cur_sstype) + return; + } + halbtc8192e2ant_set_switch_sstype(btcoexist, coex_dm->cur_sstype); + + coex_dm->pre_sstype = coex_dm->cur_sstype; +} + +static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + btc8192e2ant_sw_mec1(btcoexist, false, false, false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0); +} + +static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0); + + btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0); + halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2); + + btc8192e2ant_sw_mec1(btcoexist, false, false, false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18); +} + +static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + bool low_pwr_disable = true; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + btc8192e2ant_sw_mec1(btcoexist, false, false, false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18); +} + +static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool common = false, wifi_connected = false, wifi_busy = false; + bool bt_hson = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (bt_link_info->sco_exist || bt_link_info->hid_exist) + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0); + else + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non-connected idle!!\n"); + + if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 2); + btc8192e2ant_coex_tbl_w_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + } else { + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 1); + btc8192e2ant_coex_tbl_w_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + btc8192e2ant_sw_mec1(btcoexist, false, false, false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18); + + common = true; + } else { + if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi connected + BT non connected-idle!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 2); + btc8192e2ant_coex_tbl_w_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hson) + return false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi connected + BT connected-idle!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 2); + btc8192e2ant_coex_tbl_w_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi Connected-Busy + BT Busy!!\n"); + common = false; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Wifi Connected-Idle + BT Busy!!\n"); + + halbtc8192e2ant_switch_sstype(btcoexist, + NORMAL_EXEC, 1); + btc8192e2ant_coex_tbl_w_type(btcoexist, + NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 21); + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8192e2ant_dec_btpwr(btcoexist, + NORMAL_EXEC, 0); + btc8192e2ant_sw_mec1(btcoexist, false, + false, false, false); + btc8192e2ant_sw_mec2(btcoexist, false, + false, false, 0x18); + common = true; + } + } + } + return common; +} + +static void btc8192e_int1(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + + if (coex_dm->cur_ps_tdma == 71) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->tdma_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->tdma_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } + } + } +} + +static void btc8192e_int2(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } + } + } +} + +static void btc8192e_int3(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } +} + +static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) +{ + static int up, dn, m, n, wait_cnt; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration + */ + int result; + u8 retry_cnt = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjust()\n"); + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } + } + } + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_cnt = 0; + } else { + /* accquire the BT TRx retry count from BT_Info byte2 */ + retry_cnt = coex_sta->bt_retry_cnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], retry_cnt = %d\n", retry_cnt); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n", + up, dn, m, n, wait_cnt); + result = 0; + wait_cnt++; + /* no retry in the last 2-second duration */ + if (retry_cnt == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_cnt = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex]Increase wifi duration!!\n"); + } + } else if (retry_cnt <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_cnt <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_cnt = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "Reduce wifi duration for retry<3\n"); + } + } else { + if (wait_cnt == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_cnt = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "Decrease wifi duration for retryCounter>3!!\n"); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) + btc8192e_int1(btcoexist, tx_pause, result); + else if (max_interval == 2) + btc8192e_int2(btcoexist, tx_pause, result); + else if (max_interval == 3) + btc8192e_int3(btcoexist, tx_pause, result); + } + + /* if current PsTdma not match with + * the recorded one (when scan, dhcp...), + * then we have to adjust it back to the previous record one. + */ + if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) { + bool scan = false, link = false, roam = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], PsTdma type dismatch!!!, "); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "curPsTdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); + + 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) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + coex_dm->tdma_adj_type); + else + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + } +} + +/* SCO only or SCO+PAN(HS) */ +static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4); + + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x6); + } + } +} + +static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4); + + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x6); + } + } +} + +static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + bool long_dist = false; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + if ((btrssi_state == BTC_RSSI_STATE_LOW || + btrssi_state == BTC_RSSI_STATE_STAY_LOW) && + (wifirssi_state == BTC_RSSI_STATE_LOW || + wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n"); + long_dist = true; + } + if (long_dist) { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, + 0x4); + } else { + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + } + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + if (long_dist) + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0); + else + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + + if (long_dist) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + coex_dm->auto_tdma_adjust = false; + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else { + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + true, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 2); + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + true, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + true, 0x6); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + true, 0x6); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + true, 0x6); + } + } +} + +static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(HS) only */ +static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + } + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, + false, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, false, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +static void btc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0); + btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42); + + halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3); + + if ((btrssi_state == BTC_RSSI_STATE_LOW) || + (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) || + (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else if ((btrssi_state == BTC_RSSI_STATE_HIGH) || + (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, true, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifirssi_state == BTC_RSSI_STATE_HIGH) || + (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, true, false, + false, 0x18); + } else { + btc8192e2ant_sw_mec1(btcoexist, false, true, + false, false); + btc8192e2ant_sw_mec2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], return for Manual CTRL <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + algorithm = halbtc8192e2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + halbtc8192e2ant_action_bt_inquiry(btcoexist); + return; + } + + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); + + if (halbtc8192e2ant_is_common_action(btcoexist)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant common.\n"); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex] preAlgorithm=%d, curAlgorithm=%d\n", + coex_dm->pre_algorithm, + coex_dm->cur_algorithm); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8192E_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = SCO.\n"); + halbtc8192e2ant_action_sco(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_SCO_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = SCO+PAN(EDR).\n"); + halbtc8192e2ant_action_sco_pan(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID.\n"); + halbtc8192e2ant_action_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = A2DP.\n"); + halbtc8192e2ant_action_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + halbtc8192e2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN(EDR).\n"); + halbtc8192e2ant_action_pan_edr(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HS mode.\n"); + halbtc8192e2ant_action_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN+A2DP.\n"); + halbtc8192e2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + halbtc8192e2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + btc8192e2ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = HID+A2DP.\n"); + halbtc8192e2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "Action 2-Ant, algorithm = unknown!!\n"); + /* halbtc8192e2ant_coex_alloff(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist, + bool backup) +{ + u16 u16tmp = 0; + u8 u8tmp = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 2Ant Init HW Config!!\n"); + + if (backup) { + /* backup rf 0x1e value */ + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, + 0x1e, 0xfffff); + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retrylimit = btcoexist->btc_read_2byte( + btcoexist, + 0x42a); + coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte( + btcoexist, + 0x456); + } + + /* antenna sw ctrl to bt */ + btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6); + btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24); + btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700); + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0); + + /* antenna switch control parameter */ + btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555); + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + /* 0x790[5:0] = 0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* enable PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + /* enable mailbox interface */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40); + u16tmp |= BIT9; + btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp); + + /* enable PTA I2C mailbox */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101); + u8tmp |= BIT4; + btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp); + + /* enable bt clock when wifi is disabled. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93); + u8tmp |= BIT0; + btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp); + /* enable bt clock when suspend. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT0; + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); +} + +/************************************************************* + * work around function start with wa_halbtc8192e2ant_ + *************************************************************/ + +/************************************************************ + * extern function start with EXhalbtc8192e2ant_ + ************************************************************/ + +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + halbtc8192e2ant_init_hwconfig(btcoexist, true); +} + +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + halbtc8192e2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + bool roam = false, scan = false, link = false, wifi_under_5g = false; + bool bt_hson = false, wifi_busy = false; + int wifirssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ===========[Under Manual Control]==========="); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsMode(HsChnl)", + wifi_dot11_chnl, bt_hson, wifi_hs_chnl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], + coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? + ("inquiry/page scan") : + ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", stack_info->sco_exist, + stack_info->hid_exist, stack_info->pan_exist, + stack_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x ", + GLBtInfoSrc8192e2Ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "%02x %02x %02x(%d)", + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + "PS state, IPS/LPS", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", + coex_dm->cur_sstype); + CL_PRINTF(cli_buf); + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, + coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + ps_tdma_case, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, + coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit, + coex_dm->backup_ampdu_maxtime); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x40/ 0x4f", u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) + halbtc8192e2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + halbtc8192e2ant_coex_alloff(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + } +} + +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_SCAN_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + else if (BTC_SCAN_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); +} + +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_ASSOCIATE_START == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + else if (BTC_ASSOCIATE_FINISH == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); +} + +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_center_chnl; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_center_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_center_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_center_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66 = 0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + if (type == BTC_PACKET_DHCP) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], DHCP Packet notify\n"); +} + +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + bool bt_busy = false, limited_dig = false; + bool wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8192E_2ANT_MAX) + rsp_source = BT_INFO_SRC_8192E_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data = [", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length-1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + + if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + 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]; + + /* Here we need to resend some wifi info to BT + * because bt is reset and loss of the info. + */ + if ((coex_sta->bt_info_ext & BIT1)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "bit1, send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8192e2ant_media_status_notify( + btcoexist, + BTC_MEDIA_CONNECT); + else + ex_halbtc8192e2ant_media_status_notify( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT3)) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "bit3, BT NOT ignore Wlan active!\n"); + halbtc8192e2ant_IgnoreWlanAct(btcoexist, + FORCE_EXEC, + false); + } + } else { + /* BT already NOT ignore Wlan active, + * do nothing here. + */ + } + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT4)) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else {/* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8192E_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8192e2ant_update_btlink_info(btcoexist); + + if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Non-Connected idle!!!\n"); + } else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) || + (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n"); + } else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n"); + } + + if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type) +{ +} + +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + halbtc8192e2ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true); + ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist) +{ + static u8 dis_ver_info_cnt; + u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "=======================Periodical=======================\n"); + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "************************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "************************************************\n"); + } + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + halbtc8192e2ant_querybt_info(btcoexist); + halbtc8192e2ant_monitor_bt_ctr(btcoexist); + btc8192e2ant_monitor_bt_enable_dis(btcoexist); +#else + if (halbtc8192e2ant_iswifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +#endif +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h new file mode 100644 index 0000000..75e1f7d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h @@ -0,0 +1,185 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +/***************************************************************** + * The following is for 8192E 2Ant BT Co-exist definition + *****************************************************************/ +#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 + +#define BT_INFO_8192E_2ANT_B_FTP BIT7 +#define BT_INFO_8192E_2ANT_B_A2DP BIT6 +#define BT_INFO_8192E_2ANT_B_HID BIT5 +#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8192E_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2 + +enum bt_info_src_8192e_2ant { + BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_2ANT_MAX +}; + +enum bt_8192e_2ant_bt_status { + BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_2ANT_BT_STATUS_MAX +}; + +enum bt_8192e_2ant_coex_algo { + BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_2ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2, + BT_8192E_2ANT_COEX_ALGO_HID = 0x3, + BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb, + BT_8192E_2ANT_COEX_ALGO_MAX = 0xc +}; + +struct coex_dm_8192e_2ant { + /* fw mechanism */ + u8 pre_dec_bt_pwr; + u8 cur_dec_bt_pwr; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 tdma_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; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retrylimit; + u8 backup_ampdu_maxtime; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u8 pre_sstype; + u8 cur_sstype; + + u32 prera_mask; + u32 curra_mask; + u8 curra_masktype; + u8 pre_arfrtype; + u8 cur_arfrtype; + u8 pre_retrylimit_type; + u8 cur_retrylimit_type; + u8 pre_ampdutime_type; + u8 cur_ampdutime_type; +}; + +struct coex_sta_8192e_2ant { + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/**************************************************************** + * The following is interface which will notify coex module. + ****************************************************************/ +void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist); -- cgit v0.10.2 From f5b5869095819970333dc9de54eed5c552407d35 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:43 -0500 Subject: rtlwifi: btcoexist: Modify driver to support BT coexistence in rtl8723be This patch adds the routines found in the V062814 Realtek version. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c new file mode 100644 index 0000000..e4948c8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -0,0 +1,3211 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +/*************************************************************** + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + ***************************************************************/ + +/*************************************************************** + * include files + ***************************************************************/ +#include "halbt_precomp.h" +/*************************************************************** + * Global variables, these are static variables + ***************************************************************/ +static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant; +static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant; +static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant; +static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant; + +static const char *const GLBtInfoSrc8723b1Ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8723b_1ant = 20130918; +static u32 glcoex_ver_8723b_1ant = 0x47; + +/*************************************************************** + * local function proto type if needed + ***************************************************************/ +/*************************************************************** + * local function start with halbtc8723b1ant_ + ***************************************************************/ +static u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +static u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, + BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_rate_mask) +{ + coex_dm->curra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, + &coex_dm->curra_mask); + + coex_dm->prera_mask = coex_dm->curra_mask; +} + +static void btc8723b1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_bmode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_bmode); + if (wifi_under_bmode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +static void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit = 8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +static void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || (coex_dm->pre_ampdu_time_type != + coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, + 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +static void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_masktype, + u8 arfr_type, u8 retry_limit_type, + u8 ampdu_time_type) +{ + switch (ra_masktype) { + case 0: /* normal mode */ + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, + 0x00000003); + break; + /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/ + case 2: + halbtc8723b1ant_updatera_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + btc8723b1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type); + halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type); +} + +static void halbtc8723b1ant_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 rxaggsize = 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, only work + * when BT control Rx aggregation size. + */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxaggsize); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0; + u32 reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +{ + static bool pre_wifi_busy; + static bool pre_under_4way, pre_bt_hs_on; + 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 halbtc8723b1ant_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 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED; + u8 numdiffprofile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + numdiffprofile++; + if (bt_link_info->hid_exist) + numdiffprofile++; + if (bt_link_info->pan_exist) + numdiffprofile++; + if (bt_link_info->a2dp_exist) + numdiffprofile++; + + if (numdiffprofile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP only\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (numdiffprofile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (numdiffprofile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (numdiffprofile >= 3) { + 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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36 */ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra ? "ON!!" : "OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + btc8723b1ant_set_sw_pen_tx_rate_adapt(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, + u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n", + (force_exec ? "force to" : ""), + val0x6c0, val0x6c4, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5aaa5aaa, 0xffffff, 0x3); + break; + case 5: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +static void halbtc8723b1ant_SetFwIgnoreWlanAct(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0; /* function enable */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723b1ant_SetFwIgnoreWlanAct(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + bool ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if ((byte1 & BIT4) && !(byte1 & BIT5)) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[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] = real_byte5; + + 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] = real_byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | + h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | + h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void halbtc8723b1ant_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 halbtc8723b1ant_LpsRpwm(struct btc_coexist *btcoexist, + bool force_exec, + u8 lps_val, u8 rpwm_val) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n", + (force_exec ? "force to" : ""), lps_val, rpwm_val); + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n", + coex_dm->cur_lps, coex_dm->cur_rpwm); + + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n", + coex_dm->pre_rpwm, coex_dm->cur_rpwm); + + return; + } + } + halbtc8723b1ant_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 halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra); + + halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void halbtc8723b1ant_SetAntPath(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool init_hw_cfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp = 0; + bool pg_ext_switch = false; + bool use_ext_switch = false; + u8 h2c_parameter[2] = {0}; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + /* [31:16] = fw ver, [15:0] = fw sub ver */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + + if ((fw_ver < 0xc0000) || pg_ext_switch) + use_ext_switch = true; + + if (init_hw_cfg) { + /*BT select s0/s1 is controlled by WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + /*Force GNT_BT to Normal */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + } else if (wifi_off) { + /*Force GNT_BT to High */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + /*BT select s0/s1 is controlled by BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0); + + /* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL + * BT Vendor 0xac = 0xf002 + */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT23; + u32tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + if (use_ext_switch) { + if (init_hw_cfg) { + /* 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); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + /* Main Ant to BT for IPS case 0x4c[23] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x1); + + /*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); + } else { + /*Aux Ant to BT for IPS case 0x4c[23] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x0); + + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /*ext switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* fixed internal switch first*/ + /* 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/* fixed internal switch S0->WiFi, S1->BT*/ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280); + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); + break; + } + + } else { + if (init_hw_cfg) { + /* 0x4c[23] = 1, 0x4c[24] = 0 Antenna control by 0x64*/ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT23; + u32tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + /*Main Ant to WiFi for IPS case 0x4c[23] = 1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x0); + + /*tell firmware "no antenna inverse"*/ + h2c_parameter[0] = 0; + h2c_parameter[1] = 0; /*internal switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /*Aux Ant to BT for IPS case 0x4c[23] = 1*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x64, 0x1, + 0x1); + + /*tell firmware "antenna inverse"*/ + h2c_parameter[0] = 1; + h2c_parameter[1] = 0; /*internal switch type*/ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* fixed external switch first*/ + /*Main->WiFi, Aux->BT*/ + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x1); + else/*Main->BT, Aux->WiFi */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, + 0x3, 0x2); + + /* internal switch setting*/ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + 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); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x280); + else + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x0); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x200); + else + btcoexist->btc_write_2byte(btcoexist, 0x948, + 0x80); + break; + } + } +} + +static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + bool wifi_busy = false; + u8 rssi_adjust_val = 0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!force_exec) { + if (coex_dm->cur_ps_tdma_on) + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ******** TDMA(on, %d) *********\n", + coex_dm->cur_ps_tdma); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ******** TDMA(off, %d) ********\n", + coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + default: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a, + 0x1a, 0x0, 0x50); + break; + case 1: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a, + 0x03, 0x10, 0x50); + + rssi_adjust_val = 11; + break; + case 2: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b, + 0x03, 0x10, 0x50); + rssi_adjust_val = 14; + break; + case 3: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d, + 0x1d, 0x0, 0x52); + break; + case 4: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, + 0x3, 0x14, 0x0); + rssi_adjust_val = 17; + break; + case 5: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15, + 0x3, 0x11, 0x10); + break; + case 6: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20, + 0x3, 0x11, 0x13); + break; + case 7: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc, + 0x5, 0x0, 0x0); + break; + case 8: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + break; + case 9: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, + 0x3, 0x10, 0x50); + rssi_adjust_val = 18; + break; + case 10: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, + 0xa, 0x0, 0x40); + break; + case 11: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x03, 0x10, 0x50); + rssi_adjust_val = 20; + break; + case 12: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a, + 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15, + 0x15, 0x0, 0x50); + break; + case 14: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21, + 0x3, 0x10, 0x52); + break; + case 15: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa, + 0x3, 0x8, 0x0); + break; + case 16: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15, + 0x3, 0x10, 0x0); + rssi_adjust_val = 18; + break; + case 18: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + rssi_adjust_val = 14; + break; + case 20: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x10); + break; + case 21: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x11); + break; + case 22: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x10); + break; + case 23: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 24: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 25: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 26: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 27: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x98); + rssi_adjust_val = 22; + break; + case 28: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25, + 0x3, 0x31, 0x0); + break; + case 29: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a, + 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14, + 0x3, 0x10, 0x50); + break; + case 31: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a, + 0x1a, 0, 0x58); + break; + case 32: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa, + 0x3, 0x10, 0x0); + break; + case 33: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25, + 0x3, 0x30, 0x90); + break; + case 34: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12, + 0x3, 0x14, 0x50); + break; + /* SoftAP only with no sta associated,BT disable , + * TDMA mode for power saving + * here softap mode screen off will cost 70-80mA for phone + */ + case 40: + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18, + 0x00, 0x10, 0x24); + break; + } + } else { + switch (type) { + case 8: /*PTA Control */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, + false, false); + break; + case 0: + default: /*Software control, Antenna at BT side */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, + false, false); + break; + case 9: /*Software control, Antenna at WiFi side */ + halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0, + 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_WIFI, + false, false); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + &rssi_adjust_val); + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool commom = false, wifi_connected = false; + bool wifi_busy = false; + + 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 && + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + commom = true; + } else if (wifi_connected && + (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + commom = true; + } else if (!wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + commom = true; + } else if (wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + commom = true; + } else if (!wifi_connected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + halbtc8723b1ant_sw_mechanism(btcoexist, false); + commom = true; + } else { + if (wifi_busy) + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + else + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + + commom = false; + } + + return commom; +} + +static void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + static s32 up, dn, m, n, wait_count; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration + */ + s32 result; + u8 retry_count = 0, bt_info_ext; + bool wifi_busy = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjustForAcl()\n"); + + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) + wifi_busy = true; + else + wifi_busy = false; + + if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /*accquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + result = 0; + wait_count++; + /* no retry in the last 2-second duration */ + if (retry_count == 0) { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi duration!!\n"); + } + } else if (retry_count <= 3) { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + if (wait_count <= 2) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); + } + } else { + if (wait_count == 1) + m++; + else + m = 1; + + if (m >= 20) + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); + } + + if (result == -1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } else if (result == 1) { + if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } + } else { /*no change */ + /*if busy / idle change */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex],********* TDMA(on, %d) ********\n", + coex_dm->cur_ps_tdma); + } + + if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->tdma_adj_type); + } + } +} + +static void btc8723b1ant_pstdmachkpwrsave(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 */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +static void halbtc8723b1ant_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); + break; + case BTC_PS_LPS_ON: + btc8723b1ant_pstdmachkpwrsave(btcoexist, true); + halbtc8723b1ant_LpsRpwm(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); + break; + case BTC_PS_LPS_OFF: + btc8723b1ant_pstdmachkpwrsave(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + +/*************************************************** + * + * Software Coex Mechanism start + * + ***************************************************/ +/* SCO only or SCO+PAN(HS) */ +static void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(HS) only */ +static void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +/*PAN(EDR)+A2DP */ +static void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/* HID+A2DP+PAN(EDR) */ +static void btc8723b1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_sw_mechanism(btcoexist, true); +} + +/***************************************************** + * + * Non-Software Coex Mechanism start + * + *****************************************************/ +static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +static void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) { + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } else if (bt_link_info->sco_exist || bt_link_info->hid_only) { + /* SCO/HID-only busy */ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else { + if (ap_enable) + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, + 0x50, 0x4); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } else { /* HID */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + struct btc_coexist *btcoexist, + u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0); + + if (bt_link_info->hid_only) { /*HID */ + btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /*A2DP */ + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + coex_dm->auto_tdma_adjust = false; + } else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8723b1ant_tdma_dur_adj_for_acl(btcoexist, + wifi_status); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { /*for low BT RSSI */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /*HID+A2DP */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->auto_tdma_adjust = false; + } else { /*for low BT RSSI*/ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + /*PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + } else if (bt_link_info->pan_only || + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + coex_dm->auto_tdma_adjust = false; + /*A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP)*/ + } else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } +} + +static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist) +{ + /* power save state */ + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoex) +{ + struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info; + + halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, + true, 22); + halbtc8723b1ant_coex_table_with_type(btcoex, + NORMAL_EXEC, 1); + } else if (bt_link_info->pan_only) { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, + true, 20); + halbtc8723b1ant_coex_table_with_type(btcoex, + NORMAL_EXEC, 2); + } else { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, + true, 20); + halbtc8723b1ant_coex_table_with_type(btcoex, + NORMAL_EXEC, 1); + } + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)){ + btc8723b1ant_act_bt_sco_hid_only_busy(btcoex, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 2); + } +} + +static void btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoex) +{ + struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info; + + halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || + (bt_link_info->sco_exist) || (bt_link_info->hid_only) || + (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 7); + } else { + halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 1); + } +} + +static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->pan_only) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +static void halbtc8723b1ant_action_wifi_connected_special_packet( + struct btc_coexist *btcoexist) +{ + bool hs_connecting = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) || + (bt_link_info->sco_exist) || (bt_link_info->hid_only) || + (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ + bool wifi_busy = false; + bool scan = false, link = false, roam = false; + bool under_4way = false, ap_enable = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect()===>\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + 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) { + if (scan) + btc8723b1ant_action_wifi_conn_scan(btcoexist); + else + halbtc8723b1ant_action_wifi_connected_special_packet( + btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + /* power save state */ + if (!ap_enable && + BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + !btcoexist->bt_link_info.hid_only) { + if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, + 0x50, 0x4); + } else { + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } else { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } +} + +static void btc8723b1ant_run_sw_coex_mech(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8723b1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (!halbtc8723b1ant_is_common_action(btcoexist)) { + switch (coex_dm->cur_algorithm) { + case BT_8723B_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = SCO.\n"); + halbtc8723b1ant_action_sco(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID.\n"); + halbtc8723b1ant_action_hid(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = A2DP.\n"); + halbtc8723b1ant_action_a2dp(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + halbtc8723b1ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + halbtc8723b1ant_action_pan_edr(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HS mode.\n"); + halbtc8723b1ant_action_pan_hs(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + halbtc8723b1ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + halbtc8723b1ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + btc8723b1ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + halbtc8723b1ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, bt_hs_on = false; + bool increase_scan_dev_num = false; + 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + increase_scan_dev_num = true; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + + 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) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, + agg_buf_size); + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; + } + + if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + } else { + if (wifi_connected) { + wifi_rssi_state = + halbtc8723b1ant_wifi_rssi_state(btcoexist, + 1, 2, 30, 0); + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b1ant_limited_tx(btcoexist, + NORMAL_EXEC, + 1, 1, 1, 1); + } else { + halbtc8723b1ant_limited_tx(btcoexist, + NORMAL_EXEC, + 1, 1, 1, 1); + } + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, + 0, 0, 0, 0); + } + } + + if (bt_link_info->sco_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x3; + } else if (bt_link_info->hid_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x5; + } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x8; + } + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + btc8723b1ant_run_sw_coex_mech(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (!wifi_connected) { + bool scan = false, link = false, roam = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is non connected-idle !!!\n"); + + 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) { + if (scan) + btc8723b1ant_action_wifi_not_conn_scan( + btcoexist); + else + btc8723b1ant_act_wifi_not_conn_asso_auth( + btcoexist); + } else { + btc8723b1ant_action_wifi_not_conn(btcoexist); + } + } else { /* wifi LPS/Busy */ + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* sw all off */ + halbtc8723b1ant_sw_mechanism(btcoexist, false); + + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist, + bool backup) +{ + u32 u32tmp = 0; + u8 u8tmp = 0; + u32 cnt_bt_cal_chk = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 1Ant Init HW Config!!\n"); + + if (backup) {/* backup rf 0x1e value */ + coex_dm->backup_arfr_cnt1 = + btcoexist->btc_read_4byte(btcoexist, 0x430); + coex_dm->backup_arfr_cnt2 = + btcoexist->btc_read_4byte(btcoexist, 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } + + /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); + /* BT goto standby while GNT_BT 1-->0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500); + + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + + /* BT calibration check */ + while (cnt_bt_cal_chk <= 20) { + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d); + cnt_bt_cal_chk++; + if (u32tmp & BIT0) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ########### BT calibration(cnt=%d) ###########\n", + cnt_bt_cal_chk); + mdelay(50); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n", + cnt_bt_cal_chk); + break; + } + } + + /* 0x790[5:0] = 0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Enable counter statistics */ + /*0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + + /*Antenna config */ + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, true, false); + /* PTA parameter */ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist) +{ + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); +} + +/************************************************************** + * work around function start with wa_halbtc8723b1ant_ + **************************************************************/ +/************************************************************** + * extern function start with EXhalbtc8723b1ant_ + **************************************************************/ + +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + + btcoexist->stop_coex_dm = false; + + halbtc8723b1ant_init_coex_dm(btcoexist); + + halbtc8723b1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, pstdmacase = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + bool roam = false, scan = false; + bool link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + s32 wifi_rssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck, wifi_link_status; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]=========="); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Ant Mech/ Ant Pos:", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "Wifi link/ roam/ scan", link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist , BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "sta/vwifi/hs/p2pGo/p2pGc", + ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0), + ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0)); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : + ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? + "non-connected idle" : + ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) ? + "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", bt_link_info->sco_exist, + bt_link_info->hid_exist, bt_link_info->pan_exist, + bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + GLBtInfoSrc8723b1Ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s/%s, (0x%x/0x%x)", + "PS state, IPS/LPS, (lps/rpwm)", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")), + btcoexist->bt_info.lps_val, + btcoexist->bt_info.rpwm_val); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if (!btcoexist->manual_control) { + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/", + "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", + "DelBA/ BtCtrlAgg/ AggSize", + (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), + (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"), + btcoexist->bt_info.agg_buf_size); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Rate Mask", btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + pstdmacase = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], + pstdmacase, coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", + "IgnWlanAct", coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, + coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0], + (u32tmp[1] & 0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8)>>3), u8tmp[1], + ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); + u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + + fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) + + ((u32tmp[1] & 0xffff0000) >> 16) + + (u32tmp[1] & 0xffff) + + (u32tmp[2] & 0xffff) + + ((u32tmp[3] & 0xffff0000) >> 16) + + (u32tmp[3] & 0xffff); + fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "OFDM-CCA/OFDM-FA/CCK-FA", + u32tmp[0] & 0xffff, fa_ofdm, fa_cck); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, + coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, + coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) + halbtc8723b1ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, + false, true); + /* set PTA control */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + + halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_coex_dm(btcoexist); + halbtc8723b1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + 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_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8723b1ant_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) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + if (!wifi_connected) /* non-connected scan */ + btc8723b1ant_action_wifi_not_conn_scan(btcoexist); + else /* wifi is connected */ + btc8723b1ant_action_wifi_conn_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); + if (!wifi_connected) /* non-connected scan */ + btc8723b1ant_action_wifi_not_conn(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + 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) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + btc8723b1ant_act_wifi_not_conn_asso_auth(btcoexist); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + btc8723b1ant_action_wifi_not_conn(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifiCentralChnl; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifiCentralChnl); + + if ((BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14)) { + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifiCentralChnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66 = 0x%x\n", + h2c_parameter[0] << 16 | h2c_parameter[1] << 8 | + h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + bool 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) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multiport(btcoexist); + return; + } + + coex_sta->special_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], special Packet(%d) notify\n", type); + halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist); + } +} + +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + bool wifi_connected = false; + bool bt_busy = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length=%d, hex data = [", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + else + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + + if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + 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]; + + /* Here we need to resend some wifi info to BT + * because bt is reset and loss of the info. + */ + if (coex_sta->bt_info_ext & BIT1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); + else + ex_halbtc8723b1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } + + if (coex_sta->bt_info_ext & BIT3) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit3 check, set BT NOT ignore Wlan active!!\n"); + halbtc8723b1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here.*/ + } +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + if (coex_sta->bt_info_ext & BIT4) { + /* BT auto report already enabled, do nothing */ + } else { + halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8723b1ant_update_bt_link_info(btcoexist); + + if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n"); + /* connection exists but no busy */ + } else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = + BT_8723B_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n"); + } + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8723b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n"); + + btcoexist->stop_coex_dm = true; + + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, true); + + halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n"); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to SLEEP\n"); + btcoexist->stop_coex_dm = true; + halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, + true); + halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8723b1ant_wifi_off_hw_cfg(btcoexist); + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to WAKE UP\n"); + btcoexist->stop_coex_dm = false; + halbtc8723b1ant_init_hw_config(btcoexist, false); + halbtc8723b1ant_init_coex_dm(btcoexist); + halbtc8723b1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], *****************Coex DM Reset****************\n"); + + halbtc8723b1ant_init_hw_config(btcoexist, false); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); + halbtc8723b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist) +{ + 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8723b_1ant, + glcoex_ver_8723b_1ant, fw_ver, + bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + } + +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + halbtc8723b1ant_query_bt_info(btcoexist); + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); +#else + if (btc8723b1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + } + + coex_sta->special_pkt_period_cnt++; +#endif +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h new file mode 100644 index 0000000..75f8094 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +/********************************************************************** + * The following is for 8723B 1ANT BT Co-exist definition + **********************************************************************/ +#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 + +#define BT_INFO_8723B_1ANT_B_FTP BIT7 +#define BT_INFO_8723B_1ANT_B_A2DP BIT6 +#define BT_INFO_8723B_1ANT_B_HID BIT5 +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0)) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 + +enum _BT_INFO_SRC_8723B_1ANT { + BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_1ANT_MAX +}; + +enum _BT_8723B_1ANT_BT_STATUS { + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_BT_STATUS_MAX +}; + +enum _BT_8723B_1ANT_WIFI_STATUS { + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8723B_1ANT_WIFI_STATUS_MAX +}; + +enum _BT_8723B_1ANT_COEX_ALGO { + BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_1ANT_COEX_ALGO_HID = 0x2, + BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8723b_1ant { + /* fw mechanism */ + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 tdma_adj_type; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 prera_mask; + u32 curra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + + u8 error_condition; +}; + +struct coex_sta_8723b_1ant { + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_lps; + bool under_ips; + u32 special_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + 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_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/************************************************************************* + * The following is interface which will notify coex module. + *************************************************************************/ +void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist); -- cgit v0.10.2 From 2ec7f01c35727574953dbd884d7d45da940a25ee Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:44 -0500 Subject: rtlwifi: btcoexist: Add BT coexistence routines for driver rtl8821ae This patch adds the code needed for the new rtl8821ae driver. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c new file mode 100644 index 0000000..0b75e8c --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -0,0 +1,3010 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +/*============================================================ + * Description: + * + * This file is for RTL8821A Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + *============================================================ +*/ +/*============================================================ + * include files + *============================================================ + */ +#include "halbt_precomp.h" +/*============================================================ + * Global variables, these are static variables + *============================================================ + */ +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 const char *const glbt_info_src_8821a_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8821a_1ant = 20130816; +static u32 glcoex_ver_8821a_1ant = 0x41; + +/*============================================================ + * local function proto type if needed + * + * local function start with halbtc8821a1ant_ + *============================================================ + */ +static u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + long bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +static u8 halbtc8821a1ant_WifiRssiState(struct btc_coexist *btcoexist, + u8 index, u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + long wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= + (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void halbtc8821a1ant_update_ra_mask(struct btc_coexist *btcoexist, + bool force_exec, u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || + (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask, + &coex_dm->cur_ra_mask); + } + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +static void btc8821a1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + bool wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || + (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode*/ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, 0x430, + 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, + 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +static void halbtc8821a1ant_retry_limit(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode*/ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit = 8*/ + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +static void halbtc8821a1ant_ampdu_max_time(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode*/ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us*/ + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +static void halbtc8821a1ant_limited_tx(struct btc_coexist *btcoexist, + bool force_exec, u8 ra_mask_type, + u8 arfr_type, u8 retry_limit_type, + u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode*/ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, 0x0); + break; + case 1: /* disable cck 1/2*/ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + btc8821a1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type); + halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +static void halbtc8821a1ant_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, only work when BT control Rx agg 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 halbtc8821a1ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + u32 reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_tx_rx = 0x770; + reg_lp_tx_rx = 0x774; + + u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx); + reg_hp_tx = u4_tmp & MASKLWORD; + reg_hp_rx = (u4_tmp & MASKHWORD)>>16; + + u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx); + reg_lp_tx = u4_tmp & MASKLWORD; + reg_lp_rx = (u4_tmp & MASKHWORD)>>16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + /* reset counter*/ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8821a1ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static void halbtc8821a1ant_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 halbtc8821a1ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool bt_hs_on = false; + u8 algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No BT link exists!!!\n"); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO only\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID only\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP only\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + 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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + return algorithm; +} + +static void halbtc8821a1ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", + (enable_auto_report ? "Enabled!!" : "Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8821a1ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_auto_report) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n", + (force_exec ? "force to" : ""), ((enable_auto_report) ? + "Enabled" : "Disabled")); + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821a1ant_set_bt_auto_report(btcoexist, coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void btc8821a1ant_set_sw_pen_tx_rate(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6= Retry_Penalty*/ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36*/ + h2c_parameter[2] = 0x00; + h2c_parameter[3] = 0xf7; /*MCS7 or OFDM54*/ + h2c_parameter[4] = 0xf8; /*MCS6 or OFDM48*/ + h2c_parameter[5] = 0xf9; /*MCS5 or OFDM36*/ + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra ? "ON!!" : "OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8821a1ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + btc8821a1ant_set_sw_pen_tx_rate(btcoexist, coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8821a1ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8821a1ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", + (force_exec ? "force to" : ""), val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + coex_dm->cur_val_0x6c0 = val0x6c0; + coex_dm->cur_val_0x6c4 = val0x6c4; + coex_dm->cur_val_0x6c8 = val0x6c8; + coex_dm->cur_val_0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val_0x6c0 == coex_dm->cur_val_0x6c0) && + (coex_dm->pre_val_0x6c4 == coex_dm->cur_val_0x6c4) && + (coex_dm->pre_val_0x6c8 == coex_dm->cur_val_0x6c8) && + (coex_dm->pre_val_0x6cc == coex_dm->cur_val_0x6cc)) + return; + } + halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, + val0x6c8, val0x6cc); + + coex_dm->pre_val_0x6c0 = coex_dm->cur_val_0x6c0; + coex_dm->pre_val_0x6c4 = coex_dm->cur_val_0x6c4; + coex_dm->pre_val_0x6c8 = coex_dm->cur_val_0x6c8; + coex_dm->pre_val_0x6cc = coex_dm->cur_val_0x6cc; +} + +static void halbtc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist, + bool force_exec, u8 type) +{ + switch (type) { + case 0: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, + 0xffffff, 0x3); + break; + case 2: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555, + 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0xffffffff, + 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55ff55ff, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5afa5afa, + 0x5afa5afa, 0xffffff, 0x3); + break; + default: + break; + } +} + +static void btc8821a1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0; /* function enable*/ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +static void halbtc8821a1ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + btc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8821a1ant_set_fw_pstdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1]<<24 | + h2c_parameter[2]<<16 | + h2c_parameter[3]<<8 | + h2c_parameter[4]); + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void halbtc8821a1ant_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 halbtc8821a1ant_lps_rpwm(struct btc_coexist *btcoexist, + bool force_exec, u8 lps_val, u8 rpwm_val) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n", + (force_exec ? "force to" : ""), lps_val, rpwm_val); + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RxBeaconMode = 0x%x, LPS-RPWM = 0x%x!!\n", + coex_dm->cur_lps, coex_dm->cur_rpwm); + + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], LPS-RPWM_Last = 0x%x, LPS-RPWM_Now = 0x%x!!\n", + coex_dm->pre_rpwm, coex_dm->cur_rpwm); + + return; + } + } + halbtc8821a1ant_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 halbtc8821a1ant_sw_mechanism(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra); + + halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +static void halbtc8821a1ant_set_ant_path(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool init_hw_cfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u4_tmp = 0; + u8 h2c_parameter[2] = {0}; + + if (init_hw_cfg) { + /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT*/ + u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4_tmp &= ~BIT23; + u4_tmp |= BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x975, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /*tell firmware "antenna inverse" ==> + * WRONG firmware antenna control code.==>need fw to fix + */ + h2c_parameter[0] = 1; + 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 + */ + h2c_parameter[0] = 0; + 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 + * by BT_RFE_CTRL BT Vendor 0xac = 0xf002 + */ + u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4_tmp &= ~BIT23; + u4_tmp &= ~BIT24; + btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp); + } + + /* ext switch setting*/ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x2); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x2); + break; + } +} + +static void halbtc8821a1ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + u8 rssi_adjust_val = 0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + if (coex_dm->cur_ps_tdma_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + } + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + default: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a, + 0x1a, 0x0, 0x50); + break; + case 1: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x3a, + 0x03, 0x10, 0x50); + rssi_adjust_val = 11; + break; + case 2: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x2b, + 0x03, 0x10, 0x50); + rssi_adjust_val = 14; + break; + case 3: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d, + 0x1d, 0x0, 0x10); + break; + case 4: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15, + 0x3, 0x14, 0x0); + rssi_adjust_val = 17; + break; + case 5: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15, + 0x3, 0x11, 0x10); + break; + case 6: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, + 0x3, 0x0, 0x0); + break; + case 7: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xc, + 0x5, 0x0, 0x0); + break; + case 8: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + break; + case 9: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21, + 0x3, 0x10, 0x50); + rssi_adjust_val = 18; + break; + case 10: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, + 0xa, 0x0, 0x40); + break; + case 11: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14, + 0x03, 0x10, 0x10); + rssi_adjust_val = 20; + break; + case 12: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x0a, + 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x18, + 0x18, 0x0, 0x10); + break; + case 14: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21, + 0x3, 0x10, 0x10); + break; + case 15: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa, + 0x3, 0x8, 0x0); + break; + case 16: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15, + 0x3, 0x10, 0x0); + rssi_adjust_val = 18; + break; + case 18: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25, + 0x3, 0x10, 0x0); + rssi_adjust_val = 14; + break; + case 20: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x10); + break; + case 21: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15, + 0x03, 0x11, 0x10); + break; + case 22: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x25, + 0x03, 0x11, 0x10); + break; + case 23: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 24: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x15, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 25: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 26: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, + 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 27: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x3, 0x31, 0x98); + rssi_adjust_val = 22; + break; + case 28: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, 0x25, + 0x3, 0x31, 0x0); + break; + case 29: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, 0x1a, + 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14, + 0x3, 0x10, 0x50); + break; + case 31: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x1a, + 0x1a, 0, 0x58); + break; + case 32: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0xa, + 0x3, 0x10, 0x0); + break; + case 33: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, 0x25, + 0x3, 0x30, 0x90); + break; + case 34: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, 0x1a, + 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x12, + 0x3, 0x14, 0x50); + break; + } + } else { + /* disable PS tdma*/ + switch (type) { + case 8: /*PTA Control*/ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0, + 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + false, false); + break; + case 0: + default: /*Software control, Antenna at BT side*/ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + false, false); + break; + case 9: /*Software control, Antenna at WiFi side*/ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + false, false); + break; + case 10: /* under 5G*/ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x8, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + false, false); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + /* update pre state*/ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static bool halbtc8821a1ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool common = false, wifi_connected = false, wifi_busy = false; + + 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 && + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (wifi_connected && + (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (!wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (!wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else { + if (wifi_busy) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + } + + common = false; + } + + return common; +} + +static void btc8821a1ant_tdma_dur_adj(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + static long up, dn, m, n, wait_count; + /*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/ + long result; + u8 retry_count = 0, bt_info_ext; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjustForAcl()\n"); + + if ((BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN == + wifi_status) || + (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == + wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && + coex_dm->cur_ps_tdma != 9) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->tdma_adj_type = 2; + /*============*/ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /*accquire the BT TRx retry count from BT_Info byte2*/ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + result = 0; + wait_count++; + + if (retry_count == 0) { + /* no retry in the last 2-second duration*/ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + /* if (retry count == 0) for 2*n seconds , + * make WiFi duration wider + */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi duration!!\n"); + } + } else if (retry_count <= 3) { + /* <=3 retry in the last 2-second duration*/ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + /* if retry count< 3 for 2*2 seconds, + * shrink wifi duration + */ + if (wait_count <= 2) + m++; /* avoid bounce in two levels */ + else + m = 1; + + if (m >= 20) { + /* m max value is 20, max time is 120 s, + * recheck if adjust WiFi duration. + */ + m = 20; + } + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); + } + } else { + /* retry count > 3, if retry count > 3 happens once, + * shrink WiFi duration + */ + if (wait_count == 1) + m++; /* avoid bounce in two levels */ + else + m = 1; + /* m max value is 20, max time is 120 second, + * recheck if adjust WiFi duration. + */ + if (m >= 20) + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); + } + + if (result == -1) { + if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } else if (result == 1) { + if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } + } else { + /*no change*/ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + } + + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && + coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type*/ + halbtc8821a1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, + coex_dm->tdma_adj_type); + } + } +} + +static void btc8821a1ant_ps_tdma_check_for_pwr_save(struct btc_coexist *btcoex, + bool new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoex->btc_get(btcoex, 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*/ + halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0); + } + } else { + /* NO PS state*/ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first*/ + halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0); + } else { + /* keep state under NO PS state, do nothing.*/ + } + } +} + +static void halbtc8821a1ant_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); + break; + case BTC_PS_LPS_ON: + btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist, + true); + halbtc8821a1ant_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); + break; + case BTC_PS_LPS_OFF: + btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + +static void halbtc8821a1ant_coex_under_5g(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5); +} + +static void halbtc8821a1ant_action_wifi_only(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +} + +static void btc8821a1ant_mon_bt_en_dis(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled*/ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) { + bt_active = false; + } + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) { + bt_active = false; + } + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters = 0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + halbtc8821a1ant_action_wifi_only(btcoexist); + } + } + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + pre_bt_disabled = bt_disabled; + if (bt_disabled) { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + +/*=============================================*/ +/**/ +/* Software Coex Mechanism start*/ +/**/ +/*=============================================*/ + +/* SCO only or SCO+PAN(HS)*/ +static void halbtc8821a1ant_action_sco(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8821a1ant_action_hid(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/ +static void halbtc8821a1ant_action_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/*PAN(HS) only*/ +static void halbtc8821a1ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/*PAN(EDR)+A2DP*/ +static void halbtc8821a1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +static void halbtc8821a1ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/* HID+A2DP+PAN(EDR)*/ +static void btc8821a1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +static void halbtc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/*=============================================*/ +/**/ +/* Non-Software Coex Mechanism start*/ +/**/ +/*=============================================*/ + +static void halbtc8821a1ant_action_hs(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); +} + +static void halbtc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false; + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + + if (!wifi_connected) { + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->sco_exist) || + (bt_link_info->hid_only)) { + /* SCO/HID-only busy*/ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else { + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON, + 0x50, 0x4); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist, + u8 wifi_status) { + /* tdma and coex table*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist, + u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0); + + if (bt_link_info->hid_only) { + /*HID*/ + btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { + /*A2DP*/ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a1ant_tdma_dur_adj(btcoexist, wifi_status); + } else { + /*for low BT RSSI*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) { + /*HID+A2DP*/ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->auto_tdma_adjust = false; + } else { + /*for low BT RSSI*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->pan_only) || + (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + /*PAN(OPP, FTP), HID+PAN(OPP, FTP)*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { + /*A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP)*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } +} + +static void halbtc8821a1ant_action_wifi_not_connected( + struct btc_coexist *btcoexist) +{ + /* power save state*/ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + /* tdma and coex table*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +static void btc8821a1ant_act_wifi_not_conn_scan(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +static void halbtc8821a1ant_action_wifi_connected_scan( + struct btc_coexist *btcoexist) { + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* power save state*/ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + /* tdma and coex table*/ + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 22); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (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 { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool hs_connecting = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting); + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table*/ + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 22); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } +} + +static void halbtc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist) +{ + bool wifi_busy = false; + bool scan = false, link = false, roam = false; + bool under_4way = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect()===>\n"); + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way); + if (under_4way) { + btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + 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) { + halbtc8821a1ant_action_wifi_connected_scan(btcoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + return; + } + + /* power save state*/ + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == + coex_dm->bt_status && !btcoexist->bt_link_info.hid_only) + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + else + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table*/ + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + if (!wifi_busy) { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (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_IDLE); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } else { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (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_BUSY); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } +} + +static void btc8821a1ant_run_sw_coex_mech(struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8821a1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (!halbtc8821a1ant_is_common_action(btcoexist)) { + switch (coex_dm->cur_algorithm) { + case BT_8821A_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = SCO.\n"); + halbtc8821a1ant_action_sco(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID.\n"); + halbtc8821a1ant_action_hid(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = A2DP.\n"); + halbtc8821a1ant_action_a2dp(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + halbtc8821a1ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + halbtc8821a1ant_action_pan_edr(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HS mode.\n"); + halbtc8821a1ant_action_pan_hs(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + halbtc8821a1ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + halbtc8821a1ant_action_pan_edr_hid(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + btc8821a1ant_action_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + halbtc8821a1ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + /*halbtc8821a1ant_coex_all_off(btcoexist);*/ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +static void halbtc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + bool wifi_connected = false, bt_hs_on = false; + bool increase_scan_dev_num = false; + bool bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + bool wifi_under_5g = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism()===>\n"); + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + return; + } + + if (coex_sta->under_ips) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is under IPS !!!\n"); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + + if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + } else { + if (wifi_connected) { + wifi_rssi_state = + halbtc8821a1ant_WifiRssiState(btcoexist, 1, 2, + 30, 0); + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a1ant_limited_tx(btcoexist, + NORMAL_EXEC, 1, 1, + 1, 1); + } else { + halbtc8821a1ant_limited_tx(btcoexist, + NORMAL_EXEC, 1, 1, + 1, 1); + } + } else { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, + 0, 0, 0, 0); + } + } + + if (bt_link_info->sco_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x3; + } else if (bt_link_info->hid_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x5; + } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x8; + } + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + btc8821a1ant_run_sw_coex_mech(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (!wifi_connected) { + bool scan = false, link = false, roam = false; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], wifi is non connected-idle !!!\n"); + + 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) + btc8821a1ant_act_wifi_not_conn_scan(btcoexist); + else + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + } else { + /* wifi LPS/Busy*/ + halbtc8821a1ant_action_wifi_connected(btcoexist); + } +} + +static void halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism*/ + /* sw all off*/ + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +static void halbtc8821a1ant_init_hw_config(struct btc_coexist *btcoexist, + bool back_up) +{ + u8 u1_tmp = 0; + bool wifi_under_5g = false; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 1Ant Init HW Config!!\n"); + + if (back_up) { + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = + btcoexist->btc_read_2byte(btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = + btcoexist->btc_read_1byte(btcoexist, 0x456); + } + + /* 0x790[5:0] = 0x5*/ + u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u1_tmp &= 0xc0; + u1_tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + /*Antenna config*/ + if (wifi_under_5g) + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + true, false); + else + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + true, false); + /* PTA parameter*/ + halbtc8821a1ant_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); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +/*============================================================*/ +/* work around function start with wa_halbtc8821a1ant_*/ +/*============================================================*/ +/*============================================================*/ +/* extern function start with EXhalbtc8821a1ant_*/ +/*============================================================*/ +void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + + btcoexist->stop_coex_dm = false; + + halbtc8821a1ant_init_coex_dm(btcoexist); + + halbtc8821a1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u2_tmp[4]; + u32 u4_tmp[4]; + bool roam = false, scan = false, link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + long wifi_rssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir; + u8 wifi_dot11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Ant Mech/ Ant Pos:", + board_info->pg_ant_num, + board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8821a_1ant, + glcoex_ver_8821a_1ant, + fw_ver, bt_patch_ver, + bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, + &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, + &wifi_dot11_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, + &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsChnl(HsMode)", + wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", + (int)wifi_rssi, (int)bt_hs_rssi); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", + link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, + &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s / %s/ %s ", "Wifi status", + (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled) ? ("disabled") : + ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : + ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? + "non-connected idle" : + ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) ? + "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, + bt_link_info->hid_exist, + bt_link_info->pan_exist, + bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? + "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821a_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s/%s, (0x%x/0x%x)", + "PS state, IPS/LPS, (lps/rpwm)", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_Lps ? "LPS ON" : "LPS OFF")), + btcoexist->bt_info.lps_val, + btcoexist->bt_info.rpwm_val); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if (!btcoexist->manual_control) { + /* Sw mechanism*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s/ %s/ %d ", + "DelBA/ BtCtrlAgg/ AggSize", + (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), + (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"), + btcoexist->bt_info.agg_buf_size); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], + coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], + coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], + ps_tdma_case, + coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d ", "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + /* Hw setting*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", + coex_dm->backup_arfr_cnt1, + coex_dm->backup_arfr_cnt2, + coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]", + u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x", "0x8db[6:5]", + ((u1_tmp[0]&0x60)>>5)); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]", + (u4_tmp[0] & 0x30000000)>>28, + u4_tmp[0] & 0xff, + u1_tmp[0] & 0x3); + CL_PRINTF(cli_buf); + + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/0x4c[24:23]/0x64[0]", + u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", + u4_tmp[0], u1_tmp[0]); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x", "0xc50(dig)", + u4_tmp[0]&0xff); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d); + u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", + u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]); + CL_PRINTF(cli_buf); + + u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) + halbtc8821a1ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, true); + /*set PTA control*/ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + + halbtc8821a1ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_Lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_Lps = false; + } +} + +void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + bool wifi_connected = false, bt_hs_on = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + + halbtc8821a1ant_query_bt_info(btcoexist); + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + if (!wifi_connected) { + /* non-connected scan*/ + btc8821a1ant_act_wifi_not_conn_scan(btcoexist); + } else { + /* wifi is connected*/ + halbtc8821a1ant_action_wifi_connected_scan(btcoexist); + } + } else if (BTC_SCAN_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); + if (!wifi_connected) { + /* non-connected scan*/ + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + } else { + halbtc8821a1ant_action_wifi_connected(btcoexist); + } + } +} + +void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + bool wifi_connected = false, bt_hs_on = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + btc8821a1ant_act_wifi_not_conn_scan(btcoexist); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if (!wifi_connected) { + /* non-connected scan*/ + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + } else { + halbtc8821a1ant_action_wifi_connected(btcoexist); + } + } +} + +void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + } + + /* only 2.4G we need to inform bt the chnl mask*/ + btcoexist->btc_get(btcoexist, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + /*h2c_parameter[0] = 0x1;*/ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66 = 0x%x\n", + h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) +{ + bool bt_hs_on = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + coex_sta->special_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], special Packet(%d) notify\n", type); + btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist); + } +} + +void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + bool wifi_connected = false; + bool bt_busy = false; + bool wifi_under_5g = false; + + coex_sta->c2h_bt_info_req_sent = false; + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + rsp_source = tmp_buf[0]&0xf; + if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX) + rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length = %d, hex data = [", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length-1) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + } + + if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0]*/ + coex_sta->bt_info_c2h[rsp_source][2]&0xf; + + 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]; + + /* Here we need to resend some wifi info to BT*/ + /* because bt is reset and loss of the info.*/ + if (coex_sta->bt_info_ext & BIT1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) { + ex_halbtc8821a1ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); + } else { + ex_halbtc8821a1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } + } + + if ((coex_sta->bt_info_ext & BIT3) && !wifi_under_5g) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + halbtc8821a1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + if (!(coex_sta->bt_info_ext & BIT4)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n"); + halbtc8821a1ant_bt_auto_report(btcoexist, + FORCE_EXEC, true); + } +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan*/ + if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status*/ + if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { + /* connection exists*/ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8821a1ant_update_bt_link_info(btcoexist); + + if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (bt_info == BT_INFO_8821A_1ANT_B_CONNECTION) { + /* connection exists but no busy*/ + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) || + (bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, + BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8821a1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Halt notify\n"); + + btcoexist->stop_coex_dm = true; + + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, true); + halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + ex_halbtc8821a1ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify\n"); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to SLEEP\n"); + btcoexist->stop_coex_dm = true; + halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Pnp notify to WAKE UP\n"); + btcoexist->stop_coex_dm = false; + halbtc8821a1ant_init_hw_config(btcoexist, false); + halbtc8821a1ant_init_coex_dm(btcoexist); + halbtc8821a1ant_query_bt_info(btcoexist); + } +} + +void +ex_halbtc8821a1ant_periodical( + struct btc_coexist *btcoexist) { + static u8 dis_ver_info_cnt; + u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8821a_1ant, + glcoex_ver_8821a_1ant, + fw_ver, bt_patch_ver, + bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + } + +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + halbtc8821a1ant_query_bt_info(btcoexist); + halbtc8821a1ant_monitor_bt_ctr(btcoexist); + btc8821a1ant_mon_bt_en_dis(btcoexist); +#else + if (halbtc8821a1ant_Is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + if (coex_sta->special_pkt_period_cnt > 2) + halbtc8821a1ant_run_coexist_mechanism(btcoexist); + } + + coex_sta->special_pkt_period_cnt++; +#endif +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h new file mode 100644 index 0000000..20e9048 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h @@ -0,0 +1,188 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +/*=========================================== + * The following is for 8821A 1ANT BT Co-exist definition + *=========================================== + */ +#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0 + +#define BT_INFO_8821A_1ANT_B_FTP BIT7 +#define BT_INFO_8821A_1ANT_B_A2DP BIT6 +#define BT_INFO_8821A_1ANT_B_HID BIT5 +#define BT_INFO_8821A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8821A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8821A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8821A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8821A_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0)) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT 2 + +enum _BT_INFO_SRC_8821A_1ANT { + BT_INFO_SRC_8821A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_1ANT_MAX +}; + +enum _BT_8821A_1ANT_BT_STATUS { + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821A_1ANT_BT_STATUS_MAX +}; + +enum _BT_8821A_1ANT_WIFI_STATUS { + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8821A_1ANT_WIFI_STATUS_MAX +}; + +enum BT_8821A_1ANT_COEX_ALGO { + BT_8821A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_1ANT_COEX_ALGO_HID = 0x2, + BT_8821A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8821a_1ant { + /* fw mechanism */ + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 tdma_adj_type; + bool auto_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + u32 pre_val_0x6c0; + u32 cur_val_0x6c0; + u32 pre_val_0x6c4; + u32 cur_val_0x6c4; + u32 pre_val_0x6c8; + u32 cur_val_0x6c8; + u8 pre_val_0x6cc; + u8 cur_val_0x6cc; + /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt1; + /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + + u8 error_condition; +}; + +struct coex_sta_8821a_1ant { + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + + bool under_Lps; + bool under_ips; + u32 special_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + 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; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/*=========================================== + * The following is interface which will notify coex module. + *=========================================== + */ +void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type); +void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type); +void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmpbuf, u8 length); +void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); +void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code, + u8 op_len, u8 *data); -- cgit v0.10.2 From c96fd200e9af8ad4c4891ef579044a75c659d8c7 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:45 -0500 Subject: rtlwifi: btcoexist: Add second part of BT coexistence routines for rtl8821ae This code comes from the V062414 version of the drivers from Realtek. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c new file mode 100644 index 0000000..2322b7d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -0,0 +1,3914 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +/*============================================================ + * Description: + * + * This file is for RTL8821A Co-exist mechanism + * + * History + * 2012/08/22 Cosa first check in. + * 2012/11/14 Cosa Revise for 8821A 2Ant out sourcing. + * + *============================================================ + */ + +/*============================================================ + * include files + *============================================================ +*/ +#include "halbt_precomp.h" +/*============================================================ + * Global variables, these are static variables + *============================================================ + */ +static struct coex_dm_8821a_2ant glcoex_dm_8821a_2ant; +static struct coex_dm_8821a_2ant *coex_dm = &glcoex_dm_8821a_2ant; +static struct coex_sta_8821a_2ant glcoex_sta_8821a_2ant; +static struct coex_sta_8821a_2ant *coex_sta = &glcoex_sta_8821a_2ant; + +static const char *const glbt_info_src_8821a_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +static u32 glcoex_ver_date_8821a_2ant = 20130618; +static u32 glcoex_ver_8821a_2ant = 0x5050; + +/*============================================================ + * local function proto type if needed + *============================================================ + *============================================================ + * local function start with halbtc8821a2ant_ + *============================================================ + */ +static u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, + u8 rssi_thresh1) +{ + long bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + long tmp = rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT; + if (bt_rssi >= tmp) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else { + if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi thresh error!!\n"); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= + (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Low\n"); + } + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= + (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { + bt_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to High\n"); + } else if (bt_rssi < rssi_thresh) { + bt_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Low\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at Medium\n"); + } + } else { + if (bt_rssi < rssi_thresh1) { + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state switch to Medium\n"); + } else { + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, + "[BTCoex], BT Rssi state stay at High\n"); + } + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +static u8 halbtc8821a2ant_wifi_rssi_state(struct btc_coexist *btcoexist, + u8 index, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + long wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else { + if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI thresh error!!\n"); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_LOW) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= + (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Low\n"); + } + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) { + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to High\n"); + } else if (wifi_rssi < rssi_thresh) { + wifi_rssi_state = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Low\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at Medium\n"); + } + } else { + if (wifi_rssi < rssi_thresh1) { + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state switch to Medium\n"); + } else { + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_WIFI_RSSI_STATE, + "[BTCoex], wifi RSSI state stay at High\n"); + } + } + } + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +static void btc8821a2ant_mon_bt_en_dis(struct btc_coexist *btcoexist) +{ + static bool pre_bt_disabled; + static u32 bt_disable_cnt; + bool bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled*/ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is enabled !!\n"); + } else { + bt_disable_cnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], bt all counters = 0, %d times!!\n", + bt_disable_cnt); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is disabled !!\n"); + } + } + if (pre_bt_disabled != bt_disabled) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], BT is from %s to %s!!\n", + (pre_bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + pre_bt_disabled = bt_disabled; + } +} + +static void halbtc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist) +{ + 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; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u4tmp & MASKLWORD; + reg_hp_rx = (u4tmp & MASKHWORD)>>16; + + u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u4tmp & MASKLWORD; + reg_lp_rx = (u4tmp & MASKHWORD)>>16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[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); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, + "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +static void halbtc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT0; /* trigger */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n", + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +static u8 halbtc8821a2ant_action_algorithm(struct btc_coexist *btcoexist) +{ + struct btc_stack_info *stack_info = &btcoexist->stack_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); + + /*for win-8 stack HID report error*/ + /* 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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], No profile exists!!!\n"); + return algorithm; + } + + if (coex_sta->sco_exist) + num_of_diff_profile++; + if (coex_sta->hid_exist) + num_of_diff_profile++; + if (coex_sta->pan_exist) + num_of_diff_profile++; + if (coex_sta->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (coex_sta->sco_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO only\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + if (coex_sta->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID only\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } else if (coex_sta->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP only\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP; + } else if (coex_sta->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(HS) only\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], PAN(EDR) only\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (coex_sta->sco_exist) { + if (coex_sta->hid_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } else if (coex_sta->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } else if (coex_sta->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + PAN(EDR)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (coex_sta->hid_exist && + coex_sta->a2dp_exist) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } else if (coex_sta->hid_exist && + coex_sta->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + PAN(EDR)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (coex_sta->pan_exist && + coex_sta->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], A2DP + PAN(EDR)\n"); + 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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP ==> HID\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } else if (coex_sta->hid_exist && + coex_sta->pan_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (coex_sta->pan_exist && + coex_sta->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (coex_sta->hid_exist && + coex_sta->pan_exist && + coex_sta->a2dp_exist) { + if (bt_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + 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_hs_on) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + return algorithm; +} + +static bool halbtc8821a2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist) +{ + bool ret = false; + bool bt_hs_on = false, wifi_connected = false; + long bt_hs_rssi = 0; + u8 bt_rssi_state; + + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected)) + return false; + if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi)) + return false; + + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + if (wifi_connected) { + if (bt_hs_on) { + if (bt_hs_rssi > 37) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt power for HS mode!!\n"); + ret = true; + } + } else { + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], Need to decrease bt power for Wifi is connected!!\n"); + ret = true; + } + } + } + return ret; +} + +static void btc8821a2ant_set_fw_dac_swing_lev(struct btc_coexist *btcoexist, + u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing + * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + */ + h2c_parameter[0] = dac_swing_lvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +static void halbtc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist, + bool dec_bt_pwr) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (dec_bt_pwr) + h2c_parameter[0] |= BIT1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n", + (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +static void halbtc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist, + bool force_exec, bool dec_bt_pwr) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[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; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_dec_bt_pwr = %d, cur_dec_bt_pwr = %d\n", + coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr); + + if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr) + return; + } + halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr); + + coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr; +} + +static void btc8821a2ant_set_fw_bt_lna_constr(struct btc_coexist *btcoexist, + bool bt_lna_cons_on) +{ + u8 h2c_parameter[2] = {0}; + + h2c_parameter[0] = 0x3; /* opCode, 0x3 = BT_SET_LNA_CONSTRAIN */ + + if (bt_lna_cons_on) + h2c_parameter[1] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set BT LNA Constrain: %s, FW write 0x69 = 0x%x\n", + (bt_lna_cons_on ? "ON!!" : "OFF!!"), + h2c_parameter[0]<<8|h2c_parameter[1]); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter); +} + +static void btc8821a2_set_bt_lna_const(struct btc_coexist *btcoexist, + bool force_exec, bool bt_lna_cons_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Constrain = %s\n", + (force_exec ? "force" : ""), + ((bt_lna_cons_on) ? "ON" : "OFF")); + coex_dm->cur_bt_lna_constrain = bt_lna_cons_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_bt_lna_constrain = %d,cur_bt_lna_constrain = %d\n", + coex_dm->pre_bt_lna_constrain, + coex_dm->cur_bt_lna_constrain); + + if (coex_dm->pre_bt_lna_constrain == + coex_dm->cur_bt_lna_constrain) + return; + } + btc8821a2ant_set_fw_bt_lna_constr(btcoexist, + coex_dm->cur_bt_lna_constrain); + + coex_dm->pre_bt_lna_constrain = coex_dm->cur_bt_lna_constrain; +} + +static void halbtc8821a2ant_set_fw_bt_psd_mode(struct btc_coexist *btcoexist, + u8 bt_psd_mode) +{ + u8 h2c_parameter[2] = {0}; + + h2c_parameter[0] = 0x2; /* opCode, 0x2 = BT_SET_PSD_MODE */ + + h2c_parameter[1] = bt_psd_mode; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set BT PSD mode = 0x%x, FW write 0x69 = 0x%x\n", + h2c_parameter[1], + h2c_parameter[0]<<8|h2c_parameter[1]); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter); +} + +static void halbtc8821a2ant_set_bt_psd_mode(struct btc_coexist *btcoexist, + bool force_exec, u8 bt_psd_mode) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT PSD mode = 0x%x\n", + (force_exec ? "force" : ""), bt_psd_mode); + coex_dm->cur_bt_psd_mode = bt_psd_mode; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_bt_psd_mode = 0x%x, cur_bt_psd_mode = 0x%x\n", + coex_dm->pre_bt_psd_mode, coex_dm->cur_bt_psd_mode); + + if (coex_dm->pre_bt_psd_mode == coex_dm->cur_bt_psd_mode) + return; + } + halbtc8821a2ant_set_fw_bt_psd_mode(btcoexist, + coex_dm->cur_bt_psd_mode); + + coex_dm->pre_bt_psd_mode = coex_dm->cur_bt_psd_mode; +} + +static void halbtc8821a2ant_set_bt_auto_report(struct btc_coexist *btcoexist, + bool enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n", + (enable_auto_report ? "Enabled!!" : "Disabled!!"), + h2c_parameter[0]); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +static void halbtc8821a2ant_bt_auto_report(struct btc_coexist *btcoexist, + bool force_exec, + bool enable_auto_report) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s BT Auto report = %s\n", + (force_exec ? "force to" : ""), + ((enable_auto_report) ? "Enabled" : "Disabled")); + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n", + coex_dm->pre_bt_auto_report, + coex_dm->cur_bt_auto_report); + + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821a2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +static void halbtc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist, + bool force_exec, + u8 fw_dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec ? "force to" : ""), fw_dac_swing_lvl); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_fw_dac_swing_lvl = %d, cur_fw_dac_swing_lvl = %d\n", + coex_dm->pre_fw_dac_swing_lvl, + coex_dm->cur_fw_dac_swing_lvl); + + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + btc8821a2ant_set_fw_dac_swing_lev(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +static void btc8821a2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist, + bool rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0xffffc); + } else { + /* Resume RF Rx LPF corner + * After initialized, we can use coex_dm->bt_rf0x1e_backup + */ + if (btcoexist->initilized) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x1e, 0xfffff, + coex_dm->bt_rf0x1e_backup); + } + } +} + +static void halbtc8821a2ant_RfShrink(struct btc_coexist *btcoexist, + bool force_exec, bool rx_rf_shrink_on) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec ? "force to" : ""), + ((rx_rf_shrink_on) ? "ON" : "OFF")); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], pre_rf_rx_lpf_shrink = %d, cur_rf_rx_lpf_shrink = %d\n", + coex_dm->pre_rf_rx_lpf_shrink, + coex_dm->cur_rf_rx_lpf_shrink); + + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + btc8821a2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +static void btc8821a2ant_SetSwPenTxRateAdapt(struct btc_coexist *btcoexist, + bool low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* opCode, 0x6 = Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT0; + /*normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[2] = 0x00; + /*MCS7 or OFDM54 */ + h2c_parameter[3] = 0xf7; + /*MCS6 or OFDM48 */ + h2c_parameter[4] = 0xf8; + /*MCS5 or OFDM36 */ + h2c_parameter[5] = 0xf9; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set WiFi Low-Penalty Retry: %s", + (low_penalty_ra ? "ON!!" : "OFF!!")); + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +static void halbtc8821a2ant_low_penalty_ra(struct btc_coexist *btcoexist, + bool force_exec, bool low_penalty_ra) +{ + /*return;*/ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec ? "force to" : ""), + ((low_penalty_ra) ? "ON" : "OFF")); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], pre_low_penalty_ra = %d, cur_low_penalty_ra = %d\n", + coex_dm->pre_low_penalty_ra, + coex_dm->cur_low_penalty_ra); + + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + btc8821a2ant_SetSwPenTxRateAdapt(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +static void halbtc8821a2ant_set_dac_swing_reg(struct btc_coexist *btcoexist, + u32 level) +{ + u8 val = (u8)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val); +} + +static void btc8821a2ant_set_sw_full_dac_swing(struct btc_coexist *btcoexist, + bool sw_dac_swing_on, + u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18); +} + +static void halbtc8821a2ant_dac_swing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swing_on, + u32 dac_swing_lvl) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn DacSwing = %s, dac_swing_lvl = 0x%x\n", + (force_exec ? "force to" : ""), + ((dac_swing_on) ? "ON" : "OFF"), + dac_swing_lvl); + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], pre_dac_swing_on = %d, pre_dac_swing_lvl = 0x%x, cur_dac_swing_on = %d, cur_dac_swing_lvl = 0x%x\n", + coex_dm->pre_dac_swing_on, + coex_dm->pre_dac_swing_lvl, + coex_dm->cur_dac_swing_on, + coex_dm->cur_dac_swing_lvl); + + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == + coex_dm->cur_dac_swing_lvl)) + return; + } + mdelay(30); + btc8821a2ant_set_sw_full_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +static void halbtc8821a2ant_set_adc_back_off(struct btc_coexist *btcoexist, + bool adc_back_off) +{ + if (adc_back_off) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level On!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], BB BackOff Level Off!\n"); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); + } +} + +static void halbtc8821a2ant_adc_back_off(struct btc_coexist *btcoexist, + bool force_exec, bool adc_back_off) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec ? "force to" : ""), + ((adc_back_off) ? "ON" : "OFF")); + coex_dm->cur_adc_back_off = adc_back_off; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], pre_adc_back_off = %d, cur_adc_back_off = %d\n", + coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off); + + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +static void halbtc8821a2ant_set_coex_table(struct btc_coexist *btcoexist, + u32 val0x6c0, u32 val0x6c4, + u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, + "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +static void halbtc8821a2ant_coex_table(struct btc_coexist *btcoexist, + bool force_exec, u32 val0x6c0, + u32 val0x6c4, u32 val0x6c8, u8 val0x6cc) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, + "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n", + (force_exec ? "force to" : ""), + val0x6c0, val0x6c4, val0x6c8, val0x6cc); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], pre_val0x6c0 = 0x%x, pre_val0x6c4 = 0x%x, pre_val0x6c8 = 0x%x, pre_val0x6cc = 0x%x !!\n", + coex_dm->pre_val0x6c0, + coex_dm->pre_val0x6c4, + coex_dm->pre_val0x6c8, + coex_dm->pre_val0x6cc); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, + "[BTCoex], cur_val0x6c0 = 0x%x, cur_val0x6c4 = 0x%x, cur_val0x6c8 = 0x%x, cur_val0x6cc = 0x%x !!\n", + coex_dm->cur_val0x6c0, + coex_dm->cur_val0x6c4, + coex_dm->cur_val0x6c8, + coex_dm->cur_val0x6cc); + + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +static void halbtc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex, + bool enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT0;/* function enable */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n", + h2c_parameter[0]); + + btcoex->btc_fill_h2c(btcoex, 0x63, 1, h2c_parameter); +} + +static void halbtc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist, + bool force_exec, bool enable) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n", + coex_dm->pre_ignore_wlan_act, + coex_dm->cur_ignore_wlan_act); + + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8821a2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +static void halbtc8821a2ant_set_fw_pstdma(struct btc_coexist *btcoexist, + u8 byte1, u8 byte2, u8 byte3, + u8 byte4, u8 byte5) +{ + u8 h2c_parameter[5]; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1]<<24| + h2c_parameter[2]<<16| + h2c_parameter[3]<<8| + h2c_parameter[4]); + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +static void btc8821a2ant_sw_mech1(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; + } + + halbtc8821a2ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + halbtc8821a2ant_low_penalty_ra(btcoexist, + NORMAL_EXEC, low_penalty_ra); + + /* no limited DIG + * btc8821a2_set_bt_lna_const(btcoexist, + NORMAL_EXEC, bBTLNAConstrain); + */ +} + +static void btc8821a2ant_sw_mech2(struct btc_coexist *btcoexist, + bool agc_table_shift, + bool adc_back_off, bool sw_dac_swing, + u32 dac_swing_lvl) +{ + /* halbtc8821a2ant_AgcTable(btcoexist, NORMAL_EXEC, bAGCTableShift); */ + halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); + halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + sw_dac_swing); +} + +static void halbtc8821a2ant_set_ant_path(struct btc_coexist *btcoexist, + u8 ant_pos_type, bool init_hw_cfg, + bool wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u4tmp = 0; + u8 h2c_parameter[2] = {0}; + + if (init_hw_cfg) { + /* 0x4c[23] = 0, 0x4c[24] = 1 Antenna control by WL/BT */ + u4tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4tmp &= ~BIT23; + u4tmp |= BIT24; + 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 antenna control code. + * ==>need fw to fix + */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /* tell firmware "no antenna inverse" + * ==> WRONG firmware antenna control code. + * ==>need fw to fix + */ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_MAIN: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1); + break; + case BTC_ANT_WIFI_AT_AUX: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2); + break; + } +} + +static void halbtc8821a2ant_ps_tdma(struct btc_coexist *btcoexist, + bool force_exec, bool turn_on, u8 type) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], %s turn %s PS TDMA, type = %d\n", + (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"), + type); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x10, + 0x03, 0xf1, 0x90); + break; + case 5: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, + 0x12, 0x60, 0x90); + break; + case 7: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c, + 0x3, 0x70, 0x90); + break; + case 8: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x10, + 0x3, 0x70, 0x90); + break; + case 9: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + case 10: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, + 0x12, 0xe1, 0x90); + break; + case 11: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, + 0xa, 0xe1, 0x90); + break; + case 12: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 13: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0x60, 0x90); + break; + case 14: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x12, 0x12, 0x60, 0x90); + break; + case 15: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, + 0xa, 0x60, 0x90); + break; + case 16: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, + 0x5, 0x60, 0x90); + break; + case 17: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x2f, + 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, + 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x15, + 0x03, 0x70, 0x90); + break; + case 71: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + case 1: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x48, 0x0); + break; + default: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0, + 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +static void halbtc8821a2ant_coex_all_off(struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + btc8821a2ant_sw_mech1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, + 0x55555555, 0x55555555, 0xffff, 0x3); +} + +static void halbtc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist) +{ + halbtc8821a2ant_coex_all_off(btcoexist); +} + +static void halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555, + 0x55555555, 0xffff, 0x3); + + halbtc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18); +} + +static void halbtc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist) +{ + bool low_pwr_disable = true; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); +} + +static bool halbtc8821a2ant_is_common_action(struct btc_coexist *btcoexist) +{ + bool common = false, wifi_connected = false, wifi_busy = false; + bool low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + + 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); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi IPS + BT IPS!!\n"); + + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18); + + 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); + + if (wifi_busy) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Busy + BT IPS!!\n"); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi LPS + BT IPS!!\n"); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mech2(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); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi IPS + BT LPS!!\n"); + + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, false, false, false, false); + btc8821a2ant_sw_mech2(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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Busy + BT LPS!!\n"); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi LPS + BT LPS!!\n"); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, true, true, true, true); + btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18); + + common = true; + } else if (!wifi_connected && + (BT_8821A_2ANT_BT_STATUS_NON_IDLE == + coex_dm->bt_status)) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi IPS + BT Busy!!\n"); + + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(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) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi Busy + BT Busy!!\n"); + common = false; + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Wifi LPS + BT Busy!!\n"); + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 21); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, true); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, false); + + common = true; + } + btc8821a2ant_sw_mech1(btcoexist, true, true, true, true); + } + return common; +} + +static void btc8821a2_int1(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + + if (coex_dm->cur_ps_tdma == 71) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->tdma_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->tdma_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } + } + } +} + +static void btc8821a2_int2(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } + } + } +} + +static void btc8821a2_int3(struct btc_coexist *btcoexist, bool tx_pause, + int result) +{ + if (tx_pause) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 1\n"); + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->tdma_adj_type = 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->tdma_adj_type = 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], TxPause = 0\n"); + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->tdma_adj_type = 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->tdma_adj_type = 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } +} + +static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist, + bool sco_hid, bool tx_pause, + u8 max_interval) +{ + static long up, dn, m, n, wait_count; + /* 0: no change, +1: increase WiFi duration, + * -1: decrease WiFi duration + */ + int result; + u8 retry_count = 0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, + "[BTCoex], TdmaDurationAdjust()\n"); + + if (coex_dm->reset_tdma_adjust) { + coex_dm->reset_tdma_adjust = false; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 13); + coex_dm->tdma_adj_type = 13; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 14); + coex_dm->tdma_adj_type = 14; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } else { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 15); + coex_dm->tdma_adj_type = 15; + } + } else { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 9); + coex_dm->tdma_adj_type = 9; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 10); + coex_dm->tdma_adj_type = 10; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } else { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 11); + coex_dm->tdma_adj_type = 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 5); + coex_dm->tdma_adj_type = 5; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 6); + coex_dm->tdma_adj_type = 6; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } else { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 7); + coex_dm->tdma_adj_type = 7; + } + } else { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 1); + coex_dm->tdma_adj_type = 1; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 2); + coex_dm->tdma_adj_type = 2; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } else { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, + true, 3); + coex_dm->tdma_adj_type = 3; + } + } + } + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* accquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], retry_count = %d\n", retry_count); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], up = %d, dn = %d, m = %d, n = %d, wait_count = %d\n", + (int)up, (int)dn, (int)m, (int)n, (int)wait_count); + result = 0; + wait_count++; + + if (retry_count == 0) { + /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { + /* if (retry count == 0) for 2*n seconds, + * make WiFi duration wider + */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Increase wifi duration!!\n"); + } + } else if (retry_count <= 3) { + /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { + /* if retry count< 3 for 2*2 seconds, + * shrink wifi duration + */ + if (wait_count <= 2) + m++; /* avoid bounce in two levels */ + else + m = 1; + /* m max value is 20, max time is 120 second, + * recheck if adjust WiFi duration. + */ + if (m >= 20) + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, + ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter<3!!\n"); + } + } else { + /* retry count > 3, if retry count > 3 happens once, + * shrink WiFi duration + */ + if (wait_count == 1) + m++; /* avoid bounce in two levels */ + else + m = 1; + /* m max value is 20, max time is 120 second, + * recheck if adjust WiFi duration. + */ + if (m >= 20) + m = 20; + + n = 3*m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], Decrease wifi duration for retryCounter>3!!\n"); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], max Interval = %d\n", max_interval); + if (max_interval == 1) + btc8821a2_int1(btcoexist, tx_pause, result); + else if (max_interval == 2) + btc8821a2_int2(btcoexist, tx_pause, result); + else if (max_interval == 3) + btc8821a2_int3(btcoexist, tx_pause, result); + } + + /* 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; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n", + coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type); + + 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) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->tdma_adj_type); + } else { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + } + } + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); +} + +/* SCO only or SCO+PAN(HS)*/ +static void halbtc8821a2ant_action_sco(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 SCO quality at 11b/g mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + } else { + /* for SCO quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, + 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* fw mechanism + * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + */ + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); /*for voice quality*/ + } else { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); /*for voice quality*/ + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism + * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); /*for voice quality*/ + } else { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 0); /*for voice quality*/ + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_action_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5a5a5a5a, 0xffff, 0x3); + } else { + /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5aea5aea, 0xffff, 0x3); + } + + 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)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + } else { + halbtc8821a2ant_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)) { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + } else { + halbtc8821a2ant_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)) { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +static void halbtc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + /* fw dac swing is called in btc8821a2ant_tdma_dur_adj() + * halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + */ + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + 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, 1); + } else { + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } 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, 1); + } else { + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + /*fw dac swing is called in btc8821a2ant_tdma_dur_adj() + *halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + */ + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + /* fw mechanism */ + if (bt_info_ext&BIT0) { + /*a2dp basic rate*/ + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2); + } else { + /*a2dp edr rate*/ + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism */ + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5aff5aff, 0xffff, 0x3); + } else { + /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5aff5aff, 0xffff, 0x3); + } + + 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)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + } else { + halbtc8821a2ant_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_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + } else { + halbtc8821a2ant_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_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(HS) only */ +static void halbtc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + 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)) { + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + true); + } else { + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, + false); + } + halbtc8821a2ant_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_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + /* fw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, true); + } else { + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, false); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + false, 1); + } else { + halbtc8821a2ant_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_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +static void halbtc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + } else { + /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5afa5afa, 0xffff, 0x3); + } + + 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_dur_adj(btcoexist, false, + false, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + false, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + true, 3); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, false, + false, false); + btc8821a2ant_sw_mech2(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_dur_adj(btcoexist, false, + false, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + false, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, false, + true, 3); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, false, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5a5f5a5f, 0xffff, 0x3); + } else { + /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5a5f5a5f, 0xffff, 0x3); + } + + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3); + /* fw mechanism */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + } else { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } else { + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + /* fw mechanism */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + } else { + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 14); + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, + 0, 2, 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5a5a5a5a, 0xffff, 0x3); + } else { + /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5a5a5a5a, 0xffff, 0x3); + } + + 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_dur_adj(btcoexist, true, + true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + true, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + true, 3); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(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_dur_adj(btcoexist, true, + false, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + false, 3); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + true, 3); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, true, + true, 3); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state, bt_info_ext; + u32 wifi_bw; + + bt_info_ext = coex_sta->bt_info_ext; + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, + 15, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0); + + if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true); + else + halbtc8821a2ant_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 */ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5f5b5f5b, 0xffffff, 0x3); + } else { + /*for HID quality & wifi performance balance at 11n mode*/ + halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, + 0x5f5b5f5b, 0xffffff, 0x3); + } + + 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_dur_adj(btcoexist, + true, true, 2); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } + } else { + if (bt_info_ext&BIT0) { + /* a2dp basic rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, true, true, + false, false); + btc8821a2ant_sw_mech2(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_dur_adj(btcoexist, + true, true, 2); + + } else { + /* a2dp edr rate */ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } + } else { + if (bt_info_ext&BIT0) { + /*a2dp basic rate*/ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } else { + /*a2dp edr rate*/ + btc8821a2ant_tdma_dur_adj(btcoexist, + true, true, 2); + } + } + + /* sw mechanism */ + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, true, false, + false, 0x18); + } else { + btc8821a2ant_sw_mech1(btcoexist, false, true, + false, false); + btc8821a2ant_sw_mech2(btcoexist, false, false, + false, 0x18); + } + } +} + +static void halbtc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist) +{ + bool wifi_under_5g = false; + u8 algorithm = 0; + + if (btcoexist->manual_control) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Manual control!!!\n"); + return; + } + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n"); + halbtc8821a2ant_coex_under_5g(btcoexist); + return; + } + + algorithm = halbtc8821a2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + halbtc8821a2ant_bt_inquiry_page(btcoexist); + return; + } + + coex_dm->cur_algorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm); + + if (halbtc8821a2ant_is_common_action(btcoexist)) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant common.\n"); + coex_dm->reset_tdma_adjust = true; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + coex_dm->reset_tdma_adjust = true; + } + switch (coex_dm->cur_algorithm) { + case BT_8821A_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + halbtc8821a2ant_action_sco(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + halbtc8821a2ant_action_hid(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + halbtc8821a2ant_action_a2dp(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + halbtc8821a2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + halbtc8821a2ant_action_pan_edr(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + halbtc8821a2ant_action_pan_hs(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + halbtc8821a2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + halbtc8821a2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + btc8821a2ant_act_hid_a2dp_pan_edr(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + halbtc8821a2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + halbtc8821a2ant_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +/*============================================================ + *work around function start with wa_halbtc8821a2ant_ + *============================================================ + *============================================================ + * extern function start with EXhalbtc8821a2ant_ + *============================================================ + */ +void ex_halbtc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist) +{ + u8 u1tmp = 0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], 2Ant Init HW Config!!\n"); + + /* backup rf 0x1e value */ + coex_dm->bt_rf0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + + /* 0x790[5:0] = 0x5 */ + u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u1tmp &= 0xc0; + u1tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp); + + /*Antenna config */ + halbtc8821a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_MAIN, true, false); + + /* PTA parameter */ + halbtc8821a2ant_coex_table(btcoexist, + FORCE_EXEC, 0x55555555, 0x55555555, + 0xffff, 0x3); + + /* Enable counter statistics */ + /*0x76e[3] = 1, WLAN_Act control by PTA*/ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +void +ex_halbtc8821a2ant_init_coex_dm( + struct btc_coexist *btcoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], Coex Mechanism Init!!\n"); + + halbtc8821a2ant_init_coex_dm(btcoexist); +} + +void +ex_halbtc8821a2ant_display_coex_info( + struct btc_coexist *btcoexist + ) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u4tmp[4]; + bool roam = false, scan = false, link = false, wifi_under_5g = false; + bool bt_hs_on = false, wifi_busy = false; + long wifi_rssi = 0, bt_hs_rssi = 0; + u32 wifi_bw, wifi_traffic_dir; + u8 wifi_dot_11_chnl, wifi_hs_chnl; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (!board_info->bt_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, + BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot_11_chnl); + btcoexist->btc_get(btcoexist, + BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d(%d)", + "Dot11 channel / HsMode(HsChnl)", + wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x ", + "H2C Wifi inform bt chnl Info", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi", + wifi_rssi, bt_hs_rssi); + CL_PRINTF(cli_buf); + + 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); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", + link, roam, scan); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s / %s/ %s ", "Wifi status", + (wifi_under_5g ? "5G" : "2.4G"), + ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : + (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), + ((!wifi_busy) ? "idle" : + ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? + "uplink" : "downlink"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", + ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : + ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) + ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE == + coex_dm->bt_status) ? "connected-idle" : "busy"))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + if (stack_info->profile_notified) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", + stack_info->sco_exist, stack_info->hid_exist, + stack_info->pan_exist, stack_info->a2dp_exist); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, + BTC_DBG_DISP_BT_LINK_INFO); + } + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821a_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + "PS state, IPS/LPS", + ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), + ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + /* Sw mechanism*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig/ btLna]", + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, + coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + if (!btcoexist->manual_control) { + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", + coex_dm->cur_dec_bt_pwr, + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + /* Hw setting*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", + coex_dm->bt_rf0x1e_backup); + CL_PRINTF(cli_buf); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ", + "0x778 (W_Act)/ 0x6cc (CoTab Sel)", + u1tmp[0], u1tmp[1]); + CL_PRINTF(cli_buf); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x8db(ADC)/0xc5b[29:25](DAC)", + ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1)); + CL_PRINTF(cli_buf); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", + u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28)); + CL_PRINTF(cli_buf); + + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/ 0x4c[24:23]/ 0x974", + u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]); + CL_PRINTF(cli_buf); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u4tmp[0], u1tmp[0]); + CL_PRINTF(cli_buf); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(DIG)/0xa0a(CCK-TH)", + u4tmp[0], u1tmp[0]); + CL_PRINTF(cli_buf); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "OFDM-FA/ CCK-FA", + u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]); + CL_PRINTF(cli_buf); + + u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8", + u4tmp[0], u4tmp[1], u4tmp[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770 (hi-pri Rx/Tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri Rx/Tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/ + u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "0x41b (mgntQ hang chk == 0xf)", + u1tmp[0]); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS ENTER notify\n"); + coex_sta->under_ips = true; + halbtc8821a2ant_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], IPS LEAVE notify\n"); + coex_sta->under_ips = false; + /*halbtc8821a2ant_init_coex_dm(btcoexist);*/ + } +} + +void ex_halbtc8821a2ant_lps_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS ENABLE notify\n"); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], LPS DISABLE notify\n"); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8821a2ant_scan_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_SCAN_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN START notify\n"); + } else if (BTC_SCAN_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], SCAN FINISH notify\n"); + } +} + +void ex_halbtc8821a2ant_connect_notify(struct btc_coexist *btcoexist, u8 type) +{ + if (BTC_ASSOCIATE_START == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT START notify\n"); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], CONNECT FINISH notify\n"); + } +} + +void ex_halbtc8821a2ant_media_status_notify(struct btc_coexist *btcoexist, + u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (BTC_MEDIA_CONNECT == type) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA connect notify\n"); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], MEDIA disconnect notify\n"); + } + + /* only 2.4G we need to inform bt the chnl mask*/ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + 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) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, + "[BTCoex], FW write 0x66 = 0x%x\n", + h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a2ant_special_packet_notify(struct btc_coexist *btcoexist, + u8 type) { + if (type == BTC_PACKET_DHCP) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], DHCP Packet notify\n"); + } +} + +void ex_halbtc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist, + u8 *tmp_buf, u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + static u32 set_bt_lna_cnt, set_bt_psd_mode; + bool bt_busy = false, limited_dig = false; + bool wifi_connected = false, bt_hs_on = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0]&0xf; + if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX) + rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Bt info[%d], length = %d, hex data = [", + rsp_source, length); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length-1) { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x]\n", tmp_buf[i]); + } else { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "0x%02x, ", tmp_buf[i]); + } + } + + if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0]*/ + coex_sta->bt_info_c2h[rsp_source][2]&0xf; + + 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]; + + /* Here we need to resend some wifi info to BT*/ + /* because bt is reset and loss of the info.*/ + if ((coex_sta->bt_info_ext & BIT1)) { + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + if (wifi_connected) { + ex_halbtc8821a2ant_media_status_notify(btcoexist, + BTC_MEDIA_CONNECT); + } else { + ex_halbtc8821a2ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } + + set_bt_psd_mode = 0; + } + if (set_bt_psd_mode <= 3) { + halbtc8821a2ant_set_bt_psd_mode(btcoexist, FORCE_EXEC, + 0x0); /*fix CH-BW mode*/ + set_bt_psd_mode++; + } + + if (coex_dm->cur_bt_lna_constrain) { + if (!(coex_sta->bt_info_ext & BIT2)) { + if (set_bt_lna_cnt <= 3) { + btc8821a2_set_bt_lna_const(btcoexist, + FORCE_EXEC, + true); + set_bt_lna_cnt++; + } + } + } else { + set_bt_lna_cnt = 0; + } + + if ((coex_sta->bt_info_ext & BIT3)) { + halbtc8821a2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } else { + /* BT already NOT ignore Wlan active, do nothing here.*/ + } + + if ((coex_sta->bt_info_ext & BIT4)) { + /* BT auto report already enabled, do nothing*/ + } else { + halbtc8821a2ant_bt_auto_report(btcoexist, + FORCE_EXEC, true); + } + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + /* check BIT2 first ==> check if bt is under inquiry or page scan*/ + if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) { + coex_sta->c2h_bt_inquiry_page = true; + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + } else { + coex_sta->c2h_bt_inquiry_page = false; + if (bt_info == 0x1) { + /* connection exists but not busy*/ + coex_sta->bt_link_exist = true; + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE; + } else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) { + /* connection exists and some link is busy*/ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + } else { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + 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; + } + + if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status) + limited_dig = true; + else + limited_dig = false; + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, + BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8821a2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a2ant_halt_notify(struct btc_coexist *btcoexist) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, + "[BTCoex], Halt notify\n"); + + halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8821a2ant_periodical(struct btc_coexist *btcoexist) +{ + static u8 dis_ver_info_cnt; + u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, + "[BTCoex], ==========================Periodical===========================\n"); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[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); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, + "[BTCoex], ****************************************************************\n"); + } + + halbtc8821a2ant_query_bt_info(btcoexist); + halbtc8821a2ant_monitor_bt_ctr(btcoexist); + btc8821a2ant_mon_bt_en_dis(btcoexist); +} diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h new file mode 100644 index 0000000..b4cf1f5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h @@ -0,0 +1,205 @@ +/****************************************************************************** + * + * Copyright(c) 2012 Realtek Corporation. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +/*=========================================== + * The following is for 8821A 2Ant BT Co-exist definition + *=========================================== +*/ +#define BT_INFO_8821A_2ANT_B_FTP BIT7 +#define BT_INFO_8821A_2ANT_B_A2DP BIT6 +#define BT_INFO_8821A_2ANT_B_HID BIT5 +#define BT_INFO_8821A_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8821A_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8821A_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8821A_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8821A_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2 + +enum _BT_INFO_SRC_8821A_2ANT { + BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_2ANT_MAX +}; + +enum _BT_8821A_2ANT_BT_STATUS { + BT_8821A_2ANT_BT_STATUS_IDLE = 0x0, + BT_8821A_2ANT_BT_STATUS_CON_IDLE = 0x1, + BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8821A_2ANT_BT_STATUS_MAX +}; + +enum _BT_8821A_2ANT_COEX_ALGO { + BT_8821A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_2ANT_COEX_ALGO_HID = 0x2, + BT_8821A_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_2ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8821a_2ant { + /* fw mechanism */ + bool pre_dec_bt_pwr; + bool cur_dec_bt_pwr; + bool pre_bt_lna_constrain; + bool cur_bt_lna_constrain; + u8 pre_bt_psd_mode; + u8 cur_bt_psd_mode; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + bool cur_ignore_wlan_act; + bool pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 tdma_adj_type; + bool reset_tdma_adjust; + bool pre_ps_tdma_on; + bool cur_ps_tdma_on; + bool pre_bt_auto_report; + bool cur_bt_auto_report; + + /* sw mechanism */ + bool pre_rf_rx_lpf_shrink; + bool cur_rf_rx_lpf_shrink; + u32 bt_rf0x1e_backup; + bool pre_low_penalty_ra; + bool cur_low_penalty_ra; + bool pre_dac_swing_on; + u32 pre_dac_swing_lvl; + bool cur_dac_swing_on; + u32 cur_dac_swing_lvl; + bool pre_adc_back_off; + bool cur_adc_back_off; + bool pre_agc_table_en; + bool cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + bool limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; +}; + +struct coex_sta_8821a_2ant { + bool bt_link_exist; + bool sco_exist; + bool a2dp_exist; + bool hid_exist; + bool pan_exist; + bool under_lps; + bool under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + bool c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX]; + bool c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; +}; + +/*=========================================== + * The following is interface which will notify coex module. + *=========================================== + */ +void +ex_halbtc8821a2ant_init_hwconfig( + struct btc_coexist *btcoexist + ); +void +ex_halbtc8821a2ant_init_coex_dm( + struct btc_coexist *btcoexist + ); +void +ex_halbtc8821a2ant_ips_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_lps_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_scan_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_connect_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_media_status_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_special_packet_notify( + struct btc_coexist *btcoexist, + u8 type + ); +void +ex_halbtc8821a2ant_bt_info_notify( + struct btc_coexist *btcoexist, + u8 *tmp_buf, + u8 length + ); +void +ex_halbtc8821a2ant_halt_notify( + struct btc_coexist *btcoexist + ); +void +ex_halbtc8821a2ant_periodical( + struct btc_coexist *btcoexist + ); +void +ex_halbtc8821a2ant_display_coex_info( + struct btc_coexist *btcoexist + ); -- cgit v0.10.2 From ed364abffd6e19bec67b7ccda8237213b8b37640 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 4 Sep 2014 16:03:46 -0500 Subject: rtlwifi: btcoexist: Update remaining old parts of the driver This patch makes halbtcoutsrc.{c,h} work with the new pieces of the driver. Also included are some modifications to various header files. Signed-off-by: Larry Finger Cc: troy_tan@realsil.com.cn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h index d76684e..39b9a33 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h @@ -37,7 +37,13 @@ #include "halbtcoutsrc.h" +#include "halbtc8192e2ant.h" +#include "halbtc8723b1ant.h" #include "halbtc8723b2ant.h" +#include "halbtc8821a2ant.h" +#include "halbtc8821a1ant.h" + +#define GetDefaultAdapter(padapter) padapter #define BIT0 0x00000001 #define BIT1 0x00000002 diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index 9b9d09a..3119e8b 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -389,7 +389,7 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) btcoexist->bt_info.reject_agg_pkt = *bool_tmp; break; case BTC_SET_BL_BT_CTRL_AGG_SIZE: - btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp; + btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp; break; case BTC_SET_BL_INC_SCAN_DEV_NUM: btcoexist->bt_info.increase_scan_dev_num = *bool_tmp; @@ -417,10 +417,10 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) /* rtlpriv->mlmepriv.scan_compensation = *u8_tmp; */ break; case BTC_SET_U1_1ANT_LPS: - btcoexist->bt_info.lps_1ant = *u8_tmp; + btcoexist->bt_info.lps_val = *u8_tmp; break; case BTC_SET_U1_1ANT_RPWM: - btcoexist->bt_info.rpwm_1ant = *u8_tmp; + btcoexist->bt_info.rpwm_val = *u8_tmp; break; /* the following are some action which will be triggered */ case BTC_SET_ACT_LEAVE_LPS: @@ -506,7 +506,7 @@ static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data) } static void halbtc_bitmask_write_1byte(void *bt_context, u32 reg_addr, - u32 bit_mask, u8 data) + u8 bit_mask, u8 data) { struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -654,7 +654,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->cli_buf = &btc_dbg_buf[0]; - btcoexist->bt_info.b_bt_ctrl_buf_size = false; + btcoexist->bt_info.bt_ctrl_buf_size = false; btcoexist->bt_info.agg_buf_size = 5; btcoexist->bt_info.increase_scan_dev_num = false; @@ -786,10 +786,8 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) } void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, - enum _RT_MEDIA_STATUS media_status) + enum rt_media_status media_status) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 status; if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -846,8 +844,6 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type) { - struct rtl_priv *rtlpriv = btcoexist->adapter; - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 stack_op_type; if (!halbtc_is_bt_coexist_available(btcoexist)) diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index e90af4b..eae1937 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -66,10 +66,6 @@ #define BTC_ANT_WIFI_AT_CPL_MAIN 0 #define BTC_ANT_WIFI_AT_CPL_AUX 1 -#define BTC_ANT_PATH_WIFI 0 -#define BTC_ANT_PATH_BT 1 -#define BTC_ANT_PATH_PTA 2 - enum btc_chip_interface { BTC_INTF_UNKNOWN = 0, BTC_INTF_PCI = 1, @@ -79,7 +75,7 @@ enum btc_chip_interface { BTC_INTF_MAX }; -enum BTC_CHIP_TYPE { +enum btc_chip_type { BTC_CHIP_UNDEF = 0, BTC_CHIP_CSR_BC4 = 1, BTC_CHIP_CSR_BC8 = 2, @@ -89,11 +85,12 @@ enum BTC_CHIP_TYPE { BTC_CHIP_MAX }; -enum BTC_MSG_TYPE { +enum btc_msg_type { BTC_MSG_INTERFACE = 0x0, BTC_MSG_ALGORITHM = 0x1, BTC_MSG_MAX }; + extern u32 btc_dbg_type[]; /* following is for BTC_MSG_INTERFACE */ @@ -112,20 +109,15 @@ extern u32 btc_dbg_type[]; #define ALGO_TRACE_SW_DETAIL BIT8 #define ALGO_TRACE_SW_EXEC BIT9 -#define BT_COEX_ANT_TYPE_PG 0 -#define BT_COEX_ANT_TYPE_ANTDIV 1 -#define BT_COEX_ANT_TYPE_DETECTED 2 -#define BTC_MIMO_PS_STATIC 0 -#define BTC_MIMO_PS_DYNAMIC 1 -#define BTC_RATE_DISABLE 0 -#define BTC_RATE_ENABLE 1 -#define BTC_ANT_PATH_WIFI 0 -#define BTC_ANT_PATH_BT 1 -#define BTC_ANT_PATH_PTA 2 - +/* following is for wifi link status */ +#define WIFI_STA_CONNECTED BIT0 +#define WIFI_AP_CONNECTED BIT1 +#define WIFI_HS_CONNECTED BIT2 +#define WIFI_P2P_GO_CONNECTED BIT3 +#define WIFI_P2P_GC_CONNECTED BIT4 #define CL_SPRINTF snprintf -#define CL_PRINTF(buf) printk("%s", buf) +#define CL_PRINTF printk #define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ do { \ @@ -134,47 +126,6 @@ extern u32 btc_dbg_type[]; } \ } while (0) -#define BTC_PRINT_F(dbgtype, dbgflag, printstr, ...) \ - do { \ - if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ - pr_info("%s: ", __func__); \ - printk(printstr, ##__VA_ARGS__); \ - } \ - } while (0) - -#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr) \ - do { \ - if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \ - int __i; \ - u8 *__ptr = (u8 *)_ptr; \ - printk printstr; \ - for (__i = 0; __i < 6; __i++) \ - printk("%02X%s", __ptr[__i], (__i == 5) ? \ - "" : "-"); \ - pr_info("\n"); \ - } \ - } while (0) - -#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \ - do { \ - if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) { \ - int __i; \ - u8 *__ptr = (u8 *)_hexdata; \ - printk(_titlestring); \ - for (__i = 0; __i < (int)_hexdatalen; __i++) { \ - printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \ - == 0) ? " " : " ");\ - if (((__i + 1) % 16) == 0) \ - printk("\n"); \ - } \ - pr_debug("\n"); \ - } \ - } while (0) - -#define BTC_ANT_PATH_WIFI 0 -#define BTC_ANT_PATH_BT 1 -#define BTC_ANT_PATH_PTA 2 - #define BTC_RSSI_HIGH(_rssi_) \ ((_rssi_ == BTC_RSSI_STATE_HIGH || \ _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false) @@ -245,7 +196,6 @@ enum btc_wifi_pnp { BTC_WIFI_PNP_MAX }; - enum btc_get_type { /* type bool */ BTC_GET_BL_HS_OPERATION, @@ -274,6 +224,7 @@ enum btc_get_type { BTC_GET_U4_WIFI_BW, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_WIFI_LINK_STATUS, BTC_GET_U4_BT_PATCH_VER, /* type u1Byte */ @@ -292,7 +243,6 @@ enum btc_get_type { BTC_GET_MAX }; - enum btc_set_type { /* type bool */ BTC_SET_BL_BT_DISABLE, @@ -305,7 +255,6 @@ enum btc_set_type { /* type u1Byte */ BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, - BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, BTC_SET_UI_SCAN_SIG_COMPENSATION, BTC_SET_U1_AGG_BUF_SIZE, @@ -317,6 +266,9 @@ enum btc_set_type { /* type bool */ BTC_SET_BL_BT_SCO_BUSY, /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_U1_LPS_VAL, + BTC_SET_U1_RPWM_VAL, BTC_SET_U1_1ANT_LPS, BTC_SET_U1_1ANT_RPWM, /* type trigger some action */ @@ -380,6 +332,20 @@ enum btc_notify_type_special_packet { BTC_PACKET_MAX }; +enum hci_ext_bt_operation { + HCI_BT_OP_NONE = 0x0, + HCI_BT_OP_INQUIRY_START = 0x1, + HCI_BT_OP_INQUIRY_FINISH = 0x2, + HCI_BT_OP_PAGING_START = 0x3, + HCI_BT_OP_PAGING_SUCCESS = 0x4, + HCI_BT_OP_PAGING_UNSUCCESS = 0x5, + HCI_BT_OP_PAIRING_START = 0x6, + HCI_BT_OP_PAIRING_FINISH = 0x7, + HCI_BT_OP_BT_DEV_ENABLE = 0x8, + HCI_BT_OP_BT_DEV_DISABLE = 0x9, + HCI_BT_OP_MAX +}; + enum btc_notify_type_stack_operation { BTC_STACK_OP_NONE = 0x0, BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, @@ -387,7 +353,6 @@ enum btc_notify_type_stack_operation { BTC_STACK_OP_MAX }; - typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr); typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr); @@ -397,7 +362,7 @@ typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr); typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data); typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr, - u32 bit_mask, u8 data1b); + u8 bit_mask, u8 data1b); typedef void (*bfp_btc_w2)(void *btc_context, u32 reg_addr, u16 data); @@ -435,20 +400,22 @@ struct btc_bt_info { u8 agg_buf_size; bool limited_dig; bool reject_agg_pkt; - bool b_bt_ctrl_buf_size; + bool bt_ctrl_buf_size; bool increase_scan_dev_num; u16 bt_hci_ver; u16 bt_real_fw_ver; u8 bt_fw_ver; + bool bt_disable_low_pwr; + /* the following is for 1Ant solution */ bool bt_ctrl_lps; bool bt_pwr_save_mode; bool bt_lps_on; bool force_to_roam; u8 force_exec_pwr_cmd_cnt; - u8 lps_1ant; - u8 rpwm_1ant; + u8 lps_val; + u8 rpwm_val; u32 ra_mask; }; @@ -479,6 +446,7 @@ struct btc_statistics { u32 cnt_special_packet_notify; u32 cnt_bt_info_notify; u32 cnt_periodical; + u32 cnt_coex_dm_switch; u32 cnt_stack_operation_notify; u32 cnt_dbg_ctrl; }; @@ -531,7 +499,6 @@ struct btc_coexist { bfp_btc_set_bb_reg btc_set_bb_reg; bfp_btc_get_bb_reg btc_get_bb_reg; - bfp_btc_set_rf_reg btc_set_rf_reg; bfp_btc_get_rf_reg btc_get_rf_reg; @@ -555,13 +522,14 @@ void exhalbtc_lps_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action); void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, - enum _RT_MEDIA_STATUS media_status); + enum rt_media_status media_status); void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length); void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_halt_notify(struct btc_coexist *btcoexist); void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); +void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); void exhalbtc_periodical(struct btc_coexist *btcoexist); void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, u8 *data); diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c index 826b1a6..b9b0cb7 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c @@ -102,7 +102,7 @@ void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action) } void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, - enum _RT_MEDIA_STATUS mstatus) + enum rt_media_status mstatus) { exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus); } @@ -187,11 +187,11 @@ u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv) return num; } -enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw) +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT; + enum rt_media_status m_status = RT_MEDIA_DISCONNECT; u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h index d5218ce..ccd5a0f 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h @@ -35,7 +35,7 @@ void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type); void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype); void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action); void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, - enum _RT_MEDIA_STATUS mstatus); + enum rt_media_status mstatus); void rtl_btc_periodical(struct rtl_priv *rtlpriv); void rtl_btc_halt_notify(void); void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); @@ -49,6 +49,6 @@ struct rtl_btc_ops *rtl_btc_get_ops_pointer(void); u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv); u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv); u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv); -enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw); +enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c index 5d534df..f76c50f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c @@ -56,11 +56,11 @@ void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw) } } -static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw) +static enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT; + enum rt_media_status m_status = RT_MEDIA_DISCONNECT; u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0; diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index e44e2df..541b077 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -170,6 +170,11 @@ enum rf_tx_num { RF_TX_NUM_NONIMPLEMENT, }; +#define PACKET_NORMAL 0 +#define PACKET_DHCP 1 +#define PACKET_ARP 2 +#define PACKET_EAPOL 3 + struct txpower_info_2g { u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G]; @@ -234,8 +239,9 @@ enum hardware_type { HARDWARE_TYPE_RTL8192DU, HARDWARE_TYPE_RTL8723AE, HARDWARE_TYPE_RTL8723U, - HARDWARE_TYPE_RTL8723BE, HARDWARE_TYPE_RTL8188EE, + HARDWARE_TYPE_RTL8723BE, + HARDWARE_TYPE_RTL8192EE, HARDWARE_TYPE_RTL8821AE, HARDWARE_TYPE_RTL8812AE, @@ -428,7 +434,7 @@ enum hw_variables { HW_VAR_DATA_FILTER, }; -enum _RT_MEDIA_STATUS { +enum rt_media_status { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 }; @@ -2316,7 +2322,7 @@ struct rtl_btc_ops { void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype); void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action); void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv, - enum _RT_MEDIA_STATUS mstatus); + enum rt_media_status mstatus); void (*btc_periodical) (struct rtl_priv *rtlpriv); void (*btc_halt_notify) (void); void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv, -- cgit v0.10.2 From 6e094bd805a9b6ad2f5421125db8f604a166616c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 5 Sep 2014 00:18:48 +0200 Subject: bcma: move code for core registration into separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This cleans code a bit and will us to register cores in other places as well. The only difference with this patch is using "core_index" for setting device name. Signed-off-by: Rafał Miłecki Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 9f6b0cb..9a86352 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -120,10 +120,42 @@ static void bcma_release_core_dev(struct device *dev) kfree(core); } -static int bcma_register_cores(struct bcma_bus *bus) +static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) +{ + int err; + + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; + dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + core->dev.parent = &bus->host_pci->dev; + core->dma_dev = &bus->host_pci->dev; + core->irq = bus->host_pci->irq; + break; + case BCMA_HOSTTYPE_SOC: + core->dev.dma_mask = &core->dev.coherent_dma_mask; + core->dma_dev = &core->dev; + break; + case BCMA_HOSTTYPE_SDIO: + break; + } + + err = device_register(&core->dev); + if (err) { + bcma_err(bus, "Could not register dev for core 0x%03X\n", + core->id.id); + put_device(&core->dev); + return; + } + core->dev_registered = true; +} + +static int bcma_register_devices(struct bcma_bus *bus) { struct bcma_device *core; - int err, dev_id = 0; + int err; list_for_each_entry(core, &bus->cores, list) { /* We support that cores ourself */ @@ -143,34 +175,7 @@ static int bcma_register_cores(struct bcma_bus *bus) core->core_unit > 0) continue; - core->dev.release = bcma_release_core_dev; - core->dev.bus = &bcma_bus_type; - dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id); - - switch (bus->hosttype) { - case BCMA_HOSTTYPE_PCI: - core->dev.parent = &bus->host_pci->dev; - core->dma_dev = &bus->host_pci->dev; - core->irq = bus->host_pci->irq; - break; - case BCMA_HOSTTYPE_SOC: - core->dev.dma_mask = &core->dev.coherent_dma_mask; - core->dma_dev = &core->dev; - break; - case BCMA_HOSTTYPE_SDIO: - break; - } - - err = device_register(&core->dev); - if (err) { - bcma_err(bus, - "Could not register dev for core 0x%03X\n", - core->id.id); - put_device(&core->dev); - continue; - } - core->dev_registered = true; - dev_id++; + bcma_register_core(bus, core); } #ifdef CONFIG_BCMA_DRIVER_MIPS @@ -297,7 +302,7 @@ int bcma_bus_register(struct bcma_bus *bus) } /* Register found cores */ - bcma_register_cores(bus); + bcma_register_devices(bus); bcma_info(bus, "Bus registered\n"); -- cgit v0.10.2 From 37a7f8762d84327f8e7a8b7d7557c8415b42fc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 5 Sep 2014 00:18:49 +0200 Subject: bcma: register NAND and QSPI cores early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Northstar (ARM arch) we will use MTD subsystem to access NVRAM and SPROM. To get access to flash device we need to register these cores first. Signed-off-by: Rafał Miłecki Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 9a86352..297a2d4 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -120,6 +120,17 @@ static void bcma_release_core_dev(struct device *dev) kfree(core); } +static bool bcma_is_core_needed_early(u16 core_id) +{ + switch (core_id) { + case BCMA_CORE_NS_NAND: + case BCMA_CORE_NS_QSPI: + return true; + } + + return false; +} + static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) { int err; @@ -170,6 +181,10 @@ static int bcma_register_devices(struct bcma_bus *bus) continue; } + /* Early cores were already registered */ + if (bcma_is_core_needed_early(core->id.id)) + continue; + /* Only first GMAC core on BCM4706 is connected and working */ if (core->id.id == BCMA_CORE_4706_MAC_GBIT && core->core_unit > 0) @@ -252,6 +267,12 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_chipcommon_early_init(&bus->drv_cc); } + /* Cores providing flash access go before SPROM init */ + list_for_each_entry(core, &bus->cores, list) { + if (bcma_is_core_needed_early(core->id.id)) + bcma_register_core(bus, core); + } + /* Try to get SPROM */ err = bcma_sprom_get(bus); if (err == -ENOENT) { -- cgit v0.10.2 From 12a1b3d4c3067323c5140b405f9290cd7f1d1dac Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:09 +0530 Subject: ath9k: Fix beacon configuration for channel contexts In channel context mode, when a new context is added, mac80211 issues a bss_info_changed() notfication when preparing the connection for the new interface/context. But, this is done prior to the mgd_prepare_tx() call which is where we switch to the new context. Since the current context will be different when the earlier bss_info_changed() is handled, the beacon information for the VIF is not updated, but discarded since the rules for the current context disallows it. In the subsequent association process for the new context/vif, this becomes a problem because the beacon parameters are invalid. This causes problems with the TSF timer, causing large jumps. To fix this, check if the beacon info is being updated for a different context and if so, allow it without any checks since we limit the max. interfaces to two anyway. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b2f56d8..83f2f2f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -514,6 +514,18 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; + + if (ath9k_is_chanctx_enabled()) { + /* + * If the VIF is not present in the current channel context, + * then we can't do the usual opmode checks. Allow the + * beacon config for the VIF to be updated in this case and + * return immediately. + */ + if (sc->cur_chan != avp->chanctx) + return true; + } if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { if ((vif->type != NL80211_IFTYPE_AP) || -- cgit v0.10.2 From 602607b6e7413e4f5b194bf28deb7195b0395486 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:10 +0530 Subject: ath9k: Fix beacons for managed mode If the current opmode is managed, the ATH_OP_BEACONS flag needs to be set only when there is a primary station interface and it is associated/active. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d9be831..0b3d4d8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1067,8 +1067,8 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, if (ah->opmode == NL80211_IFTYPE_STATION) { bool changed = (iter_data.primary_sta != ctx->primary_sta); - iter_data.beacons = true; if (iter_data.primary_sta) { + iter_data.beacons = true; ath9k_set_assoc_state(sc, iter_data.primary_sta, changed); if (!ctx->primary_sta || -- cgit v0.10.2 From 9bf30ff93dae035bb60ea2f3812e44ac79b31478 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:11 +0530 Subject: ath9k: Fix panic when adding an AP interface If a station interface is already assigned to a context and is active and a second interface of type AP is added, then beaconing on the new interface has to be begin only after the BSS_CHANGED_BEACON_ENABLED flag is sent by mac80211 to the driver. But, since we issue ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL as soon as a new channel context is added, a switch occurs almost immediately before BSS_CHANGED_BEACON_ENABLED is received. When a HW reset is done for the new context, beacons are enabled for the interface since "enable_beacon" in the BSS config maintained in mac80211 is true - but the driver hasn't been notified yet. This causes a panic, since the beacon interval is zero for this interface and ath9k_cmn_beacon_config_ap() doesn't have a safety check. Fix this panic by checking if the beacon params has been cached for this context and use the "enable_beacon" flag maintained locally in the driver. Also, recalculate the summary data after the beacon params have been cached when BSS_CHANGED_BEACON_ENABLED is received. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0b3d4d8..2333776 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -916,8 +916,6 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, switch (vif->type) { case NL80211_IFTYPE_AP: iter_data->naps++; - if (vif->bss_conf.enable_beacon) - iter_data->beacons = true; break; case NL80211_IFTYPE_STATION: iter_data->nstations++; @@ -1021,6 +1019,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_vif_iter_data iter_data; + struct ath_beacon_config *cur_conf; ath_chanctx_check_active(sc, ctx); @@ -1037,8 +1036,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath_hw_setbssidmask(common); if (iter_data.naps > 0) { + cur_conf = &ctx->beacon; ath9k_hw_set_tsfadjust(ah, true); ah->opmode = NL80211_IFTYPE_AP; + if (cur_conf->enable_beacon) + iter_data.beacons = true; } else { ath9k_hw_set_tsfadjust(ah, false); @@ -1695,9 +1697,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON_ENABLED) || (changed & BSS_CHANGED_BEACON_INT) || (changed & BSS_CHANGED_BEACON_INFO)) { + ath9k_beacon_config(sc, vif, changed); if (changed & BSS_CHANGED_BEACON_ENABLED) ath9k_calculate_summary_state(sc, avp->chanctx); - ath9k_beacon_config(sc, vif, changed); } if ((avp->chanctx == sc->cur_chan) && -- cgit v0.10.2 From bd81533dbd79344232299b4669e9e3f596e618c5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:12 +0530 Subject: ath9k: Fix NoA start time calculation The start time field in the NoA attribute needs to be updated based on the TSF timer when an absence notification is sent by the P2P GO. When two channel contexts are active, continuous, cyclic NoA is announced by setting the count value to 255, but the start time is updated only once, for one beacon and the same value is sent in all subsequent beacons, even though the timestamp keeps moving. Fix this by removing the check for 'periodic_noa_duration' and assign the interface's start_time/duration values directly when there is more than one active context. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 409f912..047a76f 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -377,13 +377,13 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, tsf_time - avp->periodic_noa_start > BIT(30)) avp->periodic_noa_duration = 0; - if (ctx->active && !avp->periodic_noa_duration) { + if (ctx->active) { avp->periodic_noa_start = tsf_time; avp->periodic_noa_duration = TU_TO_USEC(cur_conf->beacon_interval) / 2 - sc->sched.channel_switch_time; noa_changed = true; - } else if (!ctx->active && avp->periodic_noa_duration) { + } else if (!ctx->active) { avp->periodic_noa_duration = 0; noa_changed = true; } -- cgit v0.10.2 From bb628eb9f0bda030c2cc9e417f52c9a344fc65fc Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:13 +0530 Subject: ath9k: Fix offchannel duration calculation Currently, different units are used for handling sc->offchannel.duration. In scan mode, it contains jiffies and in RoC mode, milliseconds is used. This causes confusion since in ath_chanctx_switch(), TU_TO_USEC is used to determine the offchannel duration, resulting in incorrect values. Fix this by using jiffies in both modes. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 047a76f..7a6ca44 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -601,7 +601,7 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, if (sc->next_chan == &sc->offchannel.chan) { sc->sched.offchannel_duration = - TU_TO_USEC(sc->offchannel.duration) + + jiffies_to_usecs(sc->offchannel.duration) + sc->sched.channel_switch_time; if (chandef) { @@ -688,7 +688,8 @@ void ath_offchannel_next(struct ath_softc *sc) } else if (sc->offchannel.roc_vif) { vif = sc->offchannel.roc_vif; sc->offchannel.chan.txpower = vif->bss_conf.txpower; - sc->offchannel.duration = sc->offchannel.roc_duration; + sc->offchannel.duration = + msecs_to_jiffies(sc->offchannel.roc_duration); sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); } else { @@ -959,8 +960,8 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) break; sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; - mod_timer(&sc->offchannel.timer, jiffies + - msecs_to_jiffies(sc->offchannel.duration)); + mod_timer(&sc->offchannel.timer, + jiffies + sc->offchannel.duration); ieee80211_ready_on_channel(sc->hw); break; case ATH_OFFCHANNEL_ROC_DONE: -- cgit v0.10.2 From fdcf1bd44f5c8892255aefffa681426049670319 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:14 +0530 Subject: ath9k: Add CTWindow support Since CTWindow can be used for improving discoverability, fill this field in the NoA Attribute properly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c690601..b4ac51e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -572,6 +572,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, /* VIFs */ /********/ +#define P2P_DEFAULT_CTWIN 10 + struct ath_vif { struct list_head list; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 7a6ca44..e73d305 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1166,6 +1166,30 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) ath9k_update_p2p_ps_timer(sc, avp); } +static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; + u8 switch_time, ctwin; + + /* + * Channel switch in multi-channel mode is deferred + * by a quarter beacon interval when handling + * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO + * interface is guaranteed to be discoverable + * for that duration after a TBTT. + */ + switch_time = cur_conf->beacon_interval / 4; + + ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + if (ctwin && (ctwin < switch_time)) + return ctwin; + + if (switch_time < P2P_DEFAULT_CTWIN) + return 0; + + return P2P_DEFAULT_CTWIN; +} + void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, struct sk_buff *skb) { @@ -1198,6 +1222,8 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, memset(noa, 0, noa_len); noa->index = avp->noa_index; + noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); + if (avp->periodic_noa_duration) { u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ca10a8b..1950c04 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -763,8 +763,9 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR | - NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE); + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_P2P_GO_CTWIN; if (!config_enabled(CONFIG_ATH9K_TX99)) { hw->wiphy->interface_modes = -- cgit v0.10.2 From 9019f646b2da436da557e58c3fe3a2dfda440a55 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:15 +0530 Subject: ath9k: Fix RX filter calculation If multiple channel contexts are active, then the opmode can be different in each context. Since the RX filter is calculated in ath_startrecv() before switching to the new opmode, the wrong filters are chosen. Fix this by calling ath9k_calculate_summary_state() before the RX module is started. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2333776..5d9f4d7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -224,6 +224,8 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; + ath9k_calculate_summary_state(sc, sc->cur_chan); + if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); return false; @@ -233,7 +235,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) sc->cur_chan->txpower, &sc->curtxpow); clear_bit(ATH_OP_HW_RESET, &common->op_flags); - ath9k_calculate_summary_state(sc, sc->cur_chan); if (!sc->cur_chan->offchannel && start) { /* restore per chanctx TSF timer */ -- cgit v0.10.2 From 19ec477f168fb514b961de5ffdb02742153728e6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:16 +0530 Subject: ath9k: Fix ath_startrecv() Since ath_startrecv() doesn't return an error value, cleanup the callsites. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b4ac51e..12cdabb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -527,7 +527,7 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc, #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); -int ath_startrecv(struct ath_softc *sc); +void ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5d9f4d7..18e5e91 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -225,15 +225,9 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) unsigned long flags; ath9k_calculate_summary_state(sc, sc->cur_chan); - - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to restart recv logic\n"); - return false; - } - + ath_startrecv(sc); ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->cur_chan->txpower, &sc->curtxpow); - clear_bit(ATH_OP_HW_RESET, &common->op_flags); if (!sc->cur_chan->offchannel && start) { diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2aaf233..04b02b5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -433,14 +433,14 @@ u32 ath_calcrxfilter(struct ath_softc *sc) } -int ath_startrecv(struct ath_softc *sc) +void ath_startrecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_rxbuf *bf, *tbf; if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ath_edma_start_recv(sc); - return 0; + return; } if (list_empty(&sc->rx.rxbuf)) @@ -463,8 +463,6 @@ int ath_startrecv(struct ath_softc *sc) start_recv: ath_opmode_init(sc); ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel); - - return 0; } static void ath_flushrecv(struct ath_softc *sc) -- cgit v0.10.2 From 3d1132d008e635c770d625f3908f201892634afe Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:17 +0530 Subject: ath9k: Fix COMP_BAR filter ATH9K_RX_FILTER_COMP_BAR is used to receive BAR completion frames and is set if the current channel is HT. When channel contexts are enabled, instead of using the mac80211 helpers, check if the current channel definition is HT. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 04b02b5..63fbc3e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -412,7 +412,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) (sc->rx.rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; - if (conf_is_ht(&sc->hw->conf)) + if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT) rfilt |= ATH9K_RX_FILTER_COMP_BAR; if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) { -- cgit v0.10.2 From fce344309944c61d748eeef530b49764f90b05bb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:18 +0530 Subject: ath9k: Fix RX filters in channel contexts Maintain the RX filter on a per-channel-context basis and not globally. Not doing so was resulting in incorrect filter calculation. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 12cdabb..4f3da18 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -314,7 +314,6 @@ struct ath_rx { bool discard_next; u32 *rxlink; u32 num_pkts; - unsigned int rxfilter; struct list_head rxbuf; struct ath_descdma rxdma; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; @@ -350,6 +349,8 @@ struct ath_chanctx { bool active; bool assigned; bool switch_after_beacon; + + unsigned int rxfilter; }; enum ath_chanctx_event { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 18e5e91..a202859 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1427,7 +1427,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - sc->rx.rxfilter = *total_flags; + spin_lock_bh(&sc->chan_lock); + sc->cur_chan->rxfilter = *total_flags; + spin_unlock_bh(&sc->chan_lock); + ath9k_ps_wakeup(sc); rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 63fbc3e..68e56d6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -387,7 +387,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->hw->conf.radar_enabled) rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; - if (sc->rx.rxfilter & FIF_PROBE_REQ) + spin_lock_bh(&sc->chan_lock); + + if (sc->cur_chan->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* @@ -398,24 +400,24 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; - if (sc->rx.rxfilter & FIF_CONTROL) + if (sc->cur_chan->rxfilter & FIF_CONTROL) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && (sc->nvifs <= 1) && - !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) + !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC)) rfilt |= ATH9K_RX_FILTER_MYBEACON; else rfilt |= ATH9K_RX_FILTER_BEACON; if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->rx.rxfilter & FIF_PSPOLL)) + (sc->cur_chan->rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT) rfilt |= ATH9K_RX_FILTER_COMP_BAR; - if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) { + if (sc->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) { /* This is needed for older chips */ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; @@ -429,6 +431,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc) test_bit(ATH_OP_SCANNING, &common->op_flags)) rfilt |= ATH9K_RX_FILTER_BEACON; + spin_unlock_bh(&sc->chan_lock); + return rfilt; } @@ -865,8 +869,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, * everything but the rate is checked here, the rate check is done * separately to avoid doing two lookups for a rate for each frame. */ - if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter)) + spin_lock_bh(&sc->chan_lock); + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, + sc->cur_chan->rxfilter)) { + spin_unlock_bh(&sc->chan_lock); return -EINVAL; + } + spin_unlock_bh(&sc->chan_lock); if (ath_is_mybeacon(common, hdr)) { RX_STAT_INC(rx_beacons); -- cgit v0.10.2 From ca529c9373bbcabf55a12e4225d625ee26fc8abb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 08:03:19 +0530 Subject: ath9k: Fix interface accounting Currently, the interface count is maintained globally, but this causes problems in RX filter calculation. Make the interface count a per-channel-context variable to fix this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4f3da18..46a1d2e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -350,6 +350,7 @@ struct ath_chanctx { bool assigned; bool switch_after_beacon; + short nvifs; unsigned int rxfilter; }; @@ -963,7 +964,6 @@ struct ath_softc { bool ps_enabled; bool ps_idle; short nbcnvifs; - short nvifs; unsigned long ps_usecount; struct ath_rx rx; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 83f2f2f..a6af855 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -183,7 +183,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, spin_unlock_bh(&cabq->axq_lock); if (skb && cabq_depth) { - if (sc->nvifs > 1) { + if (sc->cur_chan->nvifs > 1) { ath_dbg(common, BEACON, "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index d227936..5d8b5ea 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -838,7 +838,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, iter_data.nmeshes, iter_data.nwds); len += scnprintf(buf + len, sizeof(buf) - len, " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", - iter_data.nadhocs, sc->nvifs, sc->nbcnvifs); + iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs); } if (len > sizeof(buf)) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a202859..cdf1e7d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1117,7 +1117,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); if (config_enabled(CONFIG_ATH9K_TX99)) { - if (sc->nvifs >= 1) { + if (sc->cur_chan->nvifs >= 1) { mutex_unlock(&sc->mutex); return -EOPNOTSUPP; } @@ -1125,7 +1125,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); - sc->nvifs++; + sc->cur_chan->nvifs++; if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); @@ -1207,7 +1207,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_p2p_remove_vif(sc, vif); - sc->nvifs--; + sc->cur_chan->nvifs--; sc->tx99_vif = NULL; if (!ath9k_is_chanctx_enabled()) list_del(&avp->list); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 68e56d6..957a877 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -404,7 +404,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - (sc->nvifs <= 1) && + (sc->cur_chan->nvifs <= 1) && !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC)) rfilt |= ATH9K_RX_FILTER_MYBEACON; else @@ -417,7 +417,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT) rfilt |= ATH9K_RX_FILTER_COMP_BAR; - if (sc->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) { + if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) { /* This is needed for older chips */ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 2397292..8a69d08 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -174,7 +174,7 @@ static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, ssize_t len; int r; - if (sc->nvifs > 1) + if (sc->cur_chan->nvifs > 1) return -EOPNOTSUPP; len = min(count, sizeof(buf) - 1); diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 33531d9..5f30e58 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -232,7 +232,7 @@ int ath9k_suspend(struct ieee80211_hw *hw, goto fail_wow; } - if (sc->nvifs > 1) { + if (sc->cur_chan->nvifs > 1) { ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); ret = 1; goto fail_wow; -- cgit v0.10.2 From a402764452672dfe119e68edf7a21f1739b71f76 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 09:50:55 +0530 Subject: ath9k: Use a subroutine to assign HW queues Reduces code duplication. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1950c04..156a944 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -811,7 +811,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) /* allow 4 queues per channel context + * 1 cab queue + 1 offchannel tx queue */ - hw->queues = 10; + hw->queues = ATH9K_NUM_TX_QUEUES; /* last queue for offchannel */ hw->offchannel_tx_hw_queue = hw->queues - 1; hw->max_rates = 4; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cdf1e7d..1bc2369 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1104,6 +1104,20 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath9k_ps_restore(sc); } +static void ath9k_assign_hw_queues(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = i; + + if (vif->type == NL80211_IFTYPE_AP) + vif->cab_queue = hw->queues - 2; + else + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; +} + static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1112,7 +1126,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_node *an = &avp->mcast_node; - int i; mutex_lock(&sc->mutex); @@ -1135,12 +1148,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, avp->chanctx = sc->cur_chan; list_add_tail(&avp->list, &avp->chanctx->vifs); } - for (i = 0; i < IEEE80211_NUM_ACS; i++) - vif->hw_queue[i] = i; - if (vif->type == NL80211_IFTYPE_AP) - vif->cab_queue = hw->queues - 2; - else - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + + ath9k_assign_hw_queues(hw, vif); an->sc = sc; an->sta = NULL; @@ -1160,7 +1169,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; - int i; mutex_lock(&sc->mutex); @@ -1180,14 +1188,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); - for (i = 0; i < IEEE80211_NUM_ACS; i++) - vif->hw_queue[i] = i; - - if (vif->type == NL80211_IFTYPE_AP) - vif->cab_queue = hw->queues - 2; - else - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; - + ath9k_assign_hw_queues(hw, vif); ath9k_calculate_summary_state(sc, avp->chanctx); mutex_unlock(&sc->mutex); -- cgit v0.10.2 From da0162f3f0012465cc6d77c4d416fabb182713ad Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 09:50:56 +0530 Subject: ath9k: Fix offchannel operation When multiple channel contexts are active, an offchannel request will not be handled immediately, but will be queued to be handled later. But, currently, the channel definition is not copied to the local offchannel state. This breaks operation like scanning when MCC is active. Fix this by storing the offchannel parameters properly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index e73d305..a31f526 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -588,7 +588,11 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { sc->sched.offchannel_pending = true; + if (chandef) + ctx->chandef = *chandef; spin_unlock_bh(&sc->chan_lock); + ath_dbg(common, CHAN_CTX, + "Set offchannel_pending to true\n"); return; } -- cgit v0.10.2 From 367b341edbebc405d80fecd28ff973dfb7390d65 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 5 Sep 2014 09:50:57 +0530 Subject: ath9k: Fix MCC scanning Scanning is curently broken when two channel contexts are active. For example in a P2P-GO/STA setup, the offchannel timer allows HZ / 10 to elapse before initiating a switch to the next scan channel from the current operating channel, which in this case would be the P2P-GO context. But, the channel context timer might decide to switch to the STA context when an SWBA comes early and a beacon is sent out. Since pending offchannel requests are processed in EVENT_BEACON_PREPARE, this causes inconsistent scanning. Fix this by making sure that a context switch happens before processing the pending offchannel request. This also makes sure that active channel contexts will always have higher priority than offchannel operations and the scan sequence looks like this: p2p-go, sta, p2p-go, offchannel, p2p-go, sta, p2p-go, offchannel,..... The oper-channel is p2p-go, so the STA context has to switch to p2p-go again before switching offchannel. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 46a1d2e..0c071b0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -378,6 +378,7 @@ enum ath_chanctx_state { struct ath_chanctx_sched { bool beacon_pending; bool offchannel_pending; + bool wait_switch; enum ath_chanctx_state state; u8 beacon_miss; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index a31f526..522894b 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -333,7 +333,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, break; } - if (sc->sched.offchannel_pending) { + if (sc->sched.offchannel_pending && !sc->sched.wait_switch) { sc->sched.offchannel_pending = false; sc->next_chan = &sc->offchannel.chan; sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; @@ -490,6 +490,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n"); sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; + sc->sched.wait_switch = false; tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; if (sc->sched.beacon_miss >= 2) { @@ -588,6 +589,7 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { sc->sched.offchannel_pending = true; + sc->sched.wait_switch = true; if (chandef) ctx->chandef = *chandef; spin_unlock_bh(&sc->chan_lock); -- cgit v0.10.2 From 23a2f39c8f4035eade7f226eb7ada30c78d9eee3 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 8 Sep 2014 22:53:35 +0200 Subject: bcma: store more alternative addresses Each core could have more than one alternative address. There are cores with 8 alternative addresses for different functions. The PHY control in the Chip common B core is done through the 2. alternative address and not the first one. Signed-off-by: Hauke Mehrtens CC: linux-usb@vger.kernel.org Signed-off-by: John W. Linville diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index e2b9903..06be728 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -276,7 +276,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, struct bcma_device *core) { u32 tmp; - u8 i, j; + u8 i, j, k; s32 cia, cib; u8 ports[2], wrappers[2]; @@ -367,6 +367,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, core->addr = tmp; /* get & parse slave ports */ + k = 0; for (i = 0; i < ports[1]; i++) { for (j = 0; ; j++) { tmp = bcma_erom_get_addr_desc(bus, eromptr, @@ -376,9 +377,9 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, /* pr_debug("erom: slave port %d " * "has %d descriptors\n", i, j); */ break; - } else { - if (i == 0 && j == 0) - core->addr1 = tmp; + } else if (k < ARRAY_SIZE(core->addr_s)) { + core->addr_s[k] = tmp; + k++; } } } diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 205f4a3..cd6d0af 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -237,7 +237,7 @@ static int bcma_hcd_probe(struct bcma_device *dev) bcma_hcd_init_chip(dev); /* In AI chips EHCI is addrspace 0, OHCI is 1 */ - ohci_addr = dev->addr1; + ohci_addr = dev->addr_s[0]; if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) && chipinfo->rev == 0) ohci_addr = 0x18009000; diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index c1ba87d..7fc16c9 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -267,7 +267,7 @@ struct bcma_device { u8 core_unit; u32 addr; - u32 addr1; + u32 addr_s[8]; u32 wrap; void __iomem *io_addr; -- cgit v0.10.2 From 1716bcf3f76fe71e98d4851a3eb73ea3d93d4773 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 8 Sep 2014 22:53:36 +0200 Subject: bcma: add support for chipcommon B core This core is used on BCM4708 to configure the PCIe and USB3 PHYs and it contains the addresses to the Device Management unit. This will be used by the PCIe driver first. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 91290f7..838b4b9 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -1,5 +1,6 @@ bcma-y += main.o scan.o core.o sprom.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o +bcma-y += driver_chipcommon_b.o bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o bcma-y += driver_pci.o diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 09b632a..b40be43 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -50,6 +50,10 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc); extern struct platform_device bcma_pflash_dev; #endif /* CONFIG_BCMA_DRIVER_MIPS */ +/* driver_chipcommon_b.c */ +int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb); +void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb); + /* driver_chipcommon_pmu.c */ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc); u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc); diff --git a/drivers/bcma/driver_chipcommon_b.c b/drivers/bcma/driver_chipcommon_b.c new file mode 100644 index 0000000..c20b5f4 --- /dev/null +++ b/drivers/bcma/driver_chipcommon_b.c @@ -0,0 +1,61 @@ +/* + * Broadcom specific AMBA + * ChipCommon B Unit driver + * + * Copyright 2014, Hauke Mehrtens + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include +#include + +static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask, + u32 value, int timeout) +{ + unsigned long deadline = jiffies + timeout; + u32 val; + + do { + val = readl(addr); + if ((val & mask) == value) + return true; + cpu_relax(); + udelay(10); + } while (!time_after_eq(jiffies, deadline)); + + bcma_err(bus, "Timeout waiting for register %p\n", addr); + + return false; +} + +void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value) +{ + struct bcma_bus *bus = ccb->core->bus; + + writel(offset, ccb->mii + 0x00); + bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100); + writel(value, ccb->mii + 0x04); + bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100); +} +EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write); + +int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb) +{ + if (ccb->setup_done) + return 0; + + ccb->setup_done = 1; + ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE); + if (!ccb->mii) + return -ENOMEM; + + return 0; +} + +void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb) +{ + if (ccb->mii) + iounmap(ccb->mii); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 297a2d4..c421403 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -173,6 +173,7 @@ static int bcma_register_devices(struct bcma_bus *bus) switch (core->id.id) { case BCMA_CORE_4706_CHIPCOMMON: case BCMA_CORE_CHIPCOMMON: + case BCMA_CORE_NS_CHIPCOMMON_B: case BCMA_CORE_PCI: case BCMA_CORE_PCIE: case BCMA_CORE_PCIE2: @@ -287,6 +288,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_chipcommon_init(&bus->drv_cc); } + /* Init CC core */ + core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B); + if (core) { + bus->drv_cc_b.core = core; + bcma_core_chipcommon_b_init(&bus->drv_cc_b); + } + /* Init MIPS core */ core = bcma_find_core(bus, BCMA_CORE_MIPS_74K); if (core) { @@ -341,6 +349,8 @@ void bcma_bus_unregister(struct bcma_bus *bus) else if (err) bcma_err(bus, "Can not unregister GPIO driver: %i\n", err); + bcma_core_chipcommon_b_free(&bus->drv_cc_b); + cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 06be728..b3a403c 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -314,6 +314,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, /* Some specific cores don't need wrappers */ switch (core->id.id) { case BCMA_CORE_4706_MAC_GBIT_COMMON: + case BCMA_CORE_NS_CHIPCOMMON_B: /* Not used yet: case BCMA_CORE_OOB_ROUTER: */ break; default: diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 7fc16c9..6345979 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -335,6 +335,7 @@ struct bcma_bus { u8 num; struct bcma_drv_cc drv_cc; + struct bcma_drv_cc_b drv_cc_b; struct bcma_drv_pci drv_pci[2]; struct bcma_drv_pcie2 drv_pcie2; struct bcma_drv_mips drv_mips; diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 63d105c..db6fa21 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -644,6 +644,12 @@ struct bcma_drv_cc { #endif }; +struct bcma_drv_cc_b { + struct bcma_device *core; + u8 setup_done:1; + void __iomem *mii; +}; + /* Register access */ #define bcma_cc_read32(cc, offset) \ bcma_read32((cc)->core, offset) @@ -699,4 +705,6 @@ extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid); extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc); +void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value); + #endif /* LINUX_BCMA_DRIVER_CC_H_ */ -- cgit v0.10.2 From 196332f5a1e5c3ec7171742fce83d03795abf120 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 9 Sep 2014 16:21:46 -0700 Subject: Bluetooth: Fix allowing SMP Signing info PDU If the remote side is not distributing its IRK but is distributing the CSRK the next PDU after master identification is the Signing Information. This patch fixes a missing SMP_ALLOW_CMD() for this in the smp_cmd_master_ident() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 25c9040..dc575ab 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1324,6 +1324,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) SMP_DISALLOW_CMD(smp, SMP_CMD_MASTER_IDENT); if (smp->remote_key_dist & SMP_DIST_ID_KEY) SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO); + else if (smp->remote_key_dist & SMP_DIST_SIGN) + SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO); skb_pull(skb, sizeof(*rp)); -- cgit v0.10.2 From 3a7dbfb8ff943711be4221df978254ad2bc1ac46 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:41 -0700 Subject: Bluetooth: Remove unnecessary early initialization of variable We do nothing else with the auth variable in smp_cmd_pairing_rsp() besides passing it to tk_request() which in turn only cares about whether one of the sides had the MITM bit set. It is therefore unnecessary to assign a value to it until just before calling tk_request(), and this value can simply be the bit-wise or of the local and remote requirements. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index dc575ab..dbd17a0 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1003,7 +1003,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_pairing *req, *rsp = (void *) skb->data; struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; - u8 key_size, auth = SMP_AUTH_NONE; + u8 key_size, auth; int ret; BT_DBG("conn %p", conn); @@ -1044,11 +1044,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) */ smp->remote_key_dist &= rsp->resp_key_dist; - if ((req->auth_req & SMP_AUTH_BONDING) && - (rsp->auth_req & SMP_AUTH_BONDING)) - auth = SMP_AUTH_BONDING; - - auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM; + auth = (req->auth_req | rsp->auth_req); ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability); if (ret) -- cgit v0.10.2 From c05b9339c8a448a2df0c8598424ea9c0933288d1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:42 -0700 Subject: Bluetooth: Fix ignoring unknown SMP authentication requirement bits The SMP specification states that we should ignore any unknown bits from the authentication requirement. We already have a define for masking out unknown bits but we haven't used it in all places so far. This patch adds usage of the AUTH_REQ_MASK to all places that need it and ensures that we don't pass unknown bits onward to other functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index dbd17a0..ef8f96d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -949,8 +949,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; + /* We didn't start the pairing, so match remote */ + auth = req->auth_req & AUTH_REQ_MASK; + if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && - (req->auth_req & SMP_AUTH_BONDING)) + (auth & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_REQ); @@ -959,9 +962,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); - /* We didn't start the pairing, so match remote */ - auth = req->auth_req; - sec_level = authreq_to_seclevel(auth); if (sec_level > conn->hcon->pending_sec_level) conn->hcon->pending_sec_level = sec_level; @@ -1024,6 +1024,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (check_enc_key_size(conn, key_size)) return SMP_ENC_KEY_SIZE; + auth = rsp->auth_req & AUTH_REQ_MASK; + /* If we need MITM check that it can be acheived */ if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { u8 method; @@ -1044,7 +1046,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) */ smp->remote_key_dist &= rsp->resp_key_dist; - auth = (req->auth_req | rsp->auth_req); + auth |= req->auth_req; ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability); if (ret) @@ -1160,7 +1162,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_cmd_pairing cp; struct hci_conn *hcon = conn->hcon; struct smp_chan *smp; - u8 sec_level; + u8 sec_level, auth; BT_DBG("conn %p", conn); @@ -1170,7 +1172,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; - sec_level = authreq_to_seclevel(rp->auth_req); + auth = rp->auth_req & AUTH_REQ_MASK; + + sec_level = authreq_to_seclevel(auth); if (smp_sufficient_security(hcon, sec_level)) return 0; @@ -1185,13 +1189,13 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) return SMP_UNSPECIFIED; if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) && - (rp->auth_req & SMP_AUTH_BONDING)) + (auth & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; skb_pull(skb, sizeof(*rp)); memset(&cp, 0, sizeof(cp)); - build_pairing_cmd(conn, &cp, NULL, rp->auth_req); + build_pairing_cmd(conn, &cp, NULL, auth); smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], &cp, sizeof(cp)); -- cgit v0.10.2 From 24bd0bd94e0947e257c5cd6a85b0e337d953e79c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:43 -0700 Subject: Bluetooth: Centralize disallowing SMP commands to a single place All the cases where we mark SMP commands as dissalowed are their respective command handlers. We can therefore simplify the code by always clearing the bit immediately after testing it. This patch converts the corresponding test_bit() call to a test_and_clear_bit() call and also removes the now unused SMP_DISALLOW_CMD macro. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ef8f96d..be8371b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -32,7 +32,6 @@ #include "smp.h" #define SMP_ALLOW_CMD(smp, code) set_bit(code, &smp->allow_cmd) -#define SMP_DISALLOW_CMD(smp, code) clear_bit(code, &smp->allow_cmd) #define SMP_TIMEOUT msecs_to_jiffies(30000) @@ -956,8 +955,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) (auth & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; - SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_REQ); - smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); @@ -1014,8 +1011,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; - SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RSP); - skb_pull(skb, sizeof(*rsp)); req = (void *) &smp->preq[1]; @@ -1071,8 +1066,6 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(smp->pcnf)) return SMP_INVALID_PARAMS; - SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); - memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); @@ -1101,8 +1094,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(smp->rrnd)) return SMP_INVALID_PARAMS; - SMP_DISALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM); - memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd)); skb_pull(skb, sizeof(smp->rrnd)); @@ -1293,7 +1284,6 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - SMP_DISALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO); SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT); skb_pull(skb, sizeof(*rp)); @@ -1321,7 +1311,6 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_ENC_KEY; - SMP_DISALLOW_CMD(smp, SMP_CMD_MASTER_IDENT); if (smp->remote_key_dist & SMP_DIST_ID_KEY) SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO); else if (smp->remote_key_dist & SMP_DIST_SIGN) @@ -1353,7 +1342,6 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*info)) return SMP_INVALID_PARAMS; - SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_INFO); SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO); skb_pull(skb, sizeof(*info)); @@ -1380,7 +1368,6 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_ID_KEY; - SMP_DISALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO); if (smp->remote_key_dist & SMP_DIST_SIGN) SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO); @@ -1436,8 +1423,6 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) /* Mark the information as received */ smp->remote_key_dist &= ~SMP_DIST_SIGN; - SMP_DISALLOW_CMD(smp, SMP_CMD_SIGN_INFO); - skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -1482,7 +1467,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) if (code > SMP_CMD_MAX) goto drop; - if (smp && !test_bit(code, &smp->allow_cmd)) + if (smp && !test_and_clear_bit(code, &smp->allow_cmd)) goto drop; /* If we don't have a context the only allowed commands are -- cgit v0.10.2 From 1afc2a1ab6612dcc3f26db7ca1afba9cff359f1c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:44 -0700 Subject: Bluetooth: Fix SMP security level when we have no IO capabilities When the local IO capability is NoInputNoOutput any attempt to convert the remote authentication requirement to a target security level is futile. This patch makes sure that we set the target security level at most to MEDIUM if the local IO capability is NoInputNoOutput. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index be8371b..a08b077 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -959,7 +959,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); - sec_level = authreq_to_seclevel(auth); + if (conn->hcon->io_capability == 0x03) + sec_level = BT_SECURITY_MEDIUM; + else + sec_level = authreq_to_seclevel(auth); + if (sec_level > conn->hcon->pending_sec_level) conn->hcon->pending_sec_level = sec_level; @@ -1165,7 +1169,11 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) auth = rp->auth_req & AUTH_REQ_MASK; - sec_level = authreq_to_seclevel(auth); + if (hcon->io_capability == 0x03) + sec_level = BT_SECURITY_MEDIUM; + else + sec_level = authreq_to_seclevel(auth); + if (smp_sufficient_security(hcon, sec_level)) return 0; -- cgit v0.10.2 From a6f7833ca353d50de46e3532afebe4abfc5dc4d9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:45 -0700 Subject: Bluetooth: Add smp_ltk_sec_level() helper function There are several places that need to determine the security level that an LTK can provide. This patch adds a convenience function for this to help make the code more readable. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3a8381a..603a17c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4506,10 +4506,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) memcpy(cp.ltk, ltk->val, sizeof(ltk->val)); cp.handle = cpu_to_le16(conn->handle); - if (ltk->authenticated) - conn->pending_sec_level = BT_SECURITY_HIGH; - else - conn->pending_sec_level = BT_SECURITY_MEDIUM; + conn->pending_sec_level = smp_ltk_sec_level(ltk); conn->enc_key_size = ltk->enc_size; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a08b077..3700dd8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1114,7 +1114,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) if (!key) return false; - if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) + if (smp_ltk_sec_level(key) < sec_level) return false; if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 5240537..86a683a 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -125,6 +125,14 @@ enum { SMP_LTK_SLAVE, }; +static inline u8 smp_ltk_sec_level(struct smp_ltk *key) +{ + if (key->authenticated) + return BT_SECURITY_HIGH; + + return BT_SECURITY_MEDIUM; +} + /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -- cgit v0.10.2 From aeaeb4bbca520b862d3b3e7cd74c23042815a160 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:37:46 -0700 Subject: Bluetooth: Fix L2CAP information request handling for fixed channels Even if we have no connection-oriented channels we should perform the L2CAP Information Request procedures before notifying L2CAP channels of the connection. This is so that the L2CAP channel implementations can perform checks on what the remote side supports (e.g. does it support the fixed channel in question). So far the code has relied on the l2cap_do_start() function to initiate the Information Request, however l2cap_do_start() is used on a per-channel basis and only for connection-oriented channels. This means that if there are no connection-oriented channels on the system we would never start the Information Request procedure. This patch creates a new l2cap_request_info() helper function to initiate the Information Request procedure, and ensures that it is called whenever a BR/EDR connection has been established. The patch also updates fixed channels to be notified of connection readiness only once the Information Request procedure has completed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b71430c..8d53fc5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1283,6 +1283,24 @@ static void l2cap_start_connection(struct l2cap_chan *chan) } } +static void l2cap_request_info(struct l2cap_conn *conn) +{ + struct l2cap_info_req req; + + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) + return; + + req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; + conn->info_ident = l2cap_get_ident(conn); + + schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); + + l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, + sizeof(req), &req); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -1292,26 +1310,17 @@ static void l2cap_do_start(struct l2cap_chan *chan) return; } - if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { - if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) - return; - - if (l2cap_chan_check_security(chan, true) && - __l2cap_no_conn_pending(chan)) { - l2cap_start_connection(chan); - } - } else { - struct l2cap_info_req req; - req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); - - conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; - conn->info_ident = l2cap_get_ident(conn); + if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) { + l2cap_request_info(conn); + return; + } - schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); + if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) + return; - l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ, - sizeof(req), &req); - } + if (l2cap_chan_check_security(chan, true) && + __l2cap_no_conn_pending(chan)) + l2cap_start_connection(chan); } static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) @@ -1370,6 +1379,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_chan_lock(chan); if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + l2cap_chan_ready(chan); l2cap_chan_unlock(chan); continue; } @@ -1474,6 +1484,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) BT_DBG("conn %p", conn); + if (hcon->type == ACL_LINK) + l2cap_request_info(conn); + mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { @@ -1488,8 +1501,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (hcon->type == LE_LINK) { l2cap_le_start(chan); } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - l2cap_chan_ready(chan); - + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) + l2cap_chan_ready(chan); } else if (chan->state == BT_CONNECT) { l2cap_do_start(chan); } -- cgit v0.10.2 From 5be5e275ad214bbb420425754354add679d8ab68 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 17:58:54 -0700 Subject: Bluetooth: Avoid hard-coded IO capability values in SMP This is a trivial change to use a proper define for the NoInputNoOutput IO capability instead of hard-coded values. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 3700dd8..51fc7db 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -959,7 +959,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); - if (conn->hcon->io_capability == 0x03) + if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) sec_level = BT_SECURITY_MEDIUM; else sec_level = authreq_to_seclevel(auth); @@ -1169,7 +1169,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) auth = rp->auth_req & AUTH_REQ_MASK; - if (hcon->io_capability == 0x03) + if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) sec_level = BT_SECURITY_MEDIUM; else sec_level = authreq_to_seclevel(auth); -- cgit v0.10.2 From 7ed3fa20780a5efd22bb192be0908468e7c376ed Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 10 Sep 2014 22:16:35 -0700 Subject: Bluetooth: Expire RPA if encryption fails If encryption fails and we're using an RPA it may be because of a conflict with another device. To avoid repeated failures the safest action is to simply mark the RPA as expired so that a new one gets generated as soon as the connection drops. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 603a17c..8b0a2a6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2438,6 +2438,12 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) } } + /* We should disregard the current RPA and generate a new one + * whenever the encryption procedure fails. + */ + if (ev->status && conn->type == LE_LINK) + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); if (ev->status && conn->state == BT_CONNECTED) { -- cgit v0.10.2 From b47f610bd6e88f9d1032132d81b23c928a645e9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Sep 2014 13:39:54 +0300 Subject: cfg80211: clear connect keys when freeing them When freeing the connect keys, clear the memory to avoid having the key material stick around in memory "forever". Signed-off-by: Johannes Berg diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8f345da..e24fc58 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -115,7 +115,7 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, } if (WARN_ON(wdev->connect_keys)) - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = connkeys; wdev->ibss_fixed = params->channel_fixed; @@ -161,7 +161,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) ASSERT_WDEV_LOCK(wdev); - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = NULL; rdev_set_qos_map(rdev, dev, NULL); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cf178d2..e388a9f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6866,7 +6866,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); if (err) - kfree(connkeys); + kzfree(connkeys); return err; } @@ -7235,7 +7235,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) { - kfree(connkeys); + kzfree(connkeys); return -EINVAL; } memcpy(&connect.ht_capa, @@ -7253,7 +7253,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) { - kfree(connkeys); + kzfree(connkeys); return -EINVAL; } memcpy(&connect.vht_capa, @@ -7273,7 +7273,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); wdev_unlock(dev->ieee80211_ptr); if (err) - kfree(connkeys); + kzfree(connkeys); return err; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8bbeeb3..dc1668f 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -641,7 +641,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, } if (status != WLAN_STATUS_SUCCESS) { - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = NULL; wdev->ssid_len = 0; if (bss) { @@ -918,7 +918,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); if (WARN_ON(wdev->connect_keys)) { - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = NULL; } @@ -978,7 +978,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = NULL; if (wdev->conn) diff --git a/net/wireless/util.c b/net/wireless/util.c index a8b2816..5e233a5 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -797,7 +797,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) netdev_err(dev, "failed to set mgtdef %d\n", i); } - kfree(wdev->connect_keys); + kzfree(wdev->connect_keys); wdev->connect_keys = NULL; } diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index c7e5c8e..368611c 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -57,7 +57,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, err = cfg80211_connect(rdev, wdev->netdev, &wdev->wext.connect, ck, prev_bssid); if (err) - kfree(ck); + kzfree(ck); return err; } -- cgit v0.10.2 From 29c3f9c3996abea060fa6e0b9e6a30d3f0cc828c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Sep 2014 13:39:55 +0300 Subject: mac80211: clear key material when freeing keys When freeing the key, clear the memory to avoid having the key material stick around in memory "forever". Signed-off-by: Johannes Berg diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f320a04..4712150 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -422,7 +422,7 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - kfree(key); + kzfree(key); } static void __ieee80211_key_destroy(struct ieee80211_key *key, -- cgit v0.10.2 From 538c9eb8b3fd33d3a0722b2c04ec4f574eaa6e9f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Sep 2014 13:39:56 +0300 Subject: cfg80211: clear wext keys when freeing and removing them When freeing the keys stored for wireless extensions, clear the memory to avoid having the key material stick around in memory "forever". Similarly, when userspace overwrites a key, actually clear it instead of just setting the key length to zero. Signed-off-by: Johannes Berg diff --git a/net/wireless/core.c b/net/wireless/core.c index 9698fe70..55ec9be 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1007,7 +1007,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, rdev->devlist_generation++; cfg80211_mlme_purge_registrations(wdev); #ifdef CONFIG_CFG80211_WEXT - kfree(wdev->wext.keys); + kzfree(wdev->wext.keys); #endif } /* diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 11120bb..0f47948 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -496,6 +496,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, err = 0; if (!err) { if (!addr) { + memset(wdev->wext.keys->data[idx], 0, + sizeof(wdev->wext.keys->data[idx])); wdev->wext.keys->params[idx].key_len = 0; wdev->wext.keys->params[idx].cipher = 0; } -- cgit v0.10.2 From 78f686cae0c67a2edd167cbbe2f36017f0fa4b30 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Sep 2014 22:28:06 +0300 Subject: cfg80211: don't put kek/kck/replay counter on the stack There's no need to put the values on the stack, just pass a pointer to the data in the nl80211 message. This reduces stack usage and avoids potential issues with putting sensitive data on the stack. Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0d17ec9..c2c710c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1980,14 +1980,12 @@ struct cfg80211_wowlan_wakeup { /** * struct cfg80211_gtk_rekey_data - rekey data - * @kek: key encryption key - * @kck: key confirmation key - * @replay_ctr: replay counter + * @kek: key encryption key (NL80211_KEK_LEN bytes) + * @kck: key confirmation key (NL80211_KCK_LEN bytes) + * @replay_ctr: replay counter (NL80211_REPLAY_CTR_LEN bytes) */ struct cfg80211_gtk_rekey_data { - u8 kek[NL80211_KEK_LEN]; - u8 kck[NL80211_KCK_LEN]; - u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; + const u8 *kek, *kck, *replay_ctr; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e388a9f..bebdf3d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -8959,13 +8959,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN) return -ERANGE; - memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]), - NL80211_KEK_LEN); - memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]), - NL80211_KCK_LEN); - memcpy(rekey_data.replay_ctr, - nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]), - NL80211_REPLAY_CTR_LEN); + rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]); + rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]); + rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]); wdev_lock(wdev); if (!wdev->current_bss) { -- cgit v0.10.2 From 5393b917bcbb0ce0338668c89397137bd2b7436e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Sep 2014 15:00:16 +0300 Subject: cfg80211: clear nl80211 messages carrying keys after processing Clear any nl80211 messages that might contain keys after processing them to avoid leaving their data in memory "forever" after they've been freed. Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bebdf3d..e9fbd4f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9400,6 +9400,7 @@ static int nl80211_set_qos_map(struct sk_buff *skb, /* If a netdev is associated, it must be UP, P2P must be started */ #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) +#define NL80211_FLAG_CLEAR_SKB 0x20 static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) @@ -9483,8 +9484,20 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, dev_put(info->user_ptr[1]); } } + if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) rtnl_unlock(); + + /* If needed, clear the netlink message payload from the SKB + * as it might contain key data that shouldn't stick around on + * the heap after the SKB is freed. The netlink message header + * is still needed for further processing, so leave it intact. + */ + if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) { + struct nlmsghdr *nlh = nlmsg_hdr(skb); + + memset(nlmsg_data(nlh), 0, nlmsg_len(nlh)); + } } static const struct genl_ops nl80211_ops[] = { @@ -9552,7 +9565,8 @@ static const struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + NL80211_FLAG_CLEAR_SKB, }, { .cmd = NL80211_CMD_NEW_KEY, @@ -9560,7 +9574,8 @@ static const struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + NL80211_FLAG_CLEAR_SKB, }, { .cmd = NL80211_CMD_DEL_KEY, @@ -9738,7 +9753,8 @@ static const struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + NL80211_FLAG_CLEAR_SKB, }, { .cmd = NL80211_CMD_ASSOCIATE, @@ -9972,7 +9988,8 @@ static const struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + NL80211_FLAG_CLEAR_SKB, }, { .cmd = NL80211_CMD_TDLS_MGMT, -- cgit v0.10.2 From ca12c0c83334a84581bb01daaedf1009deb09204 Mon Sep 17 00:00:00 2001 From: Thomas Huehn Date: Tue, 9 Sep 2014 23:22:13 +0200 Subject: mac80211: Unify rate statistic variables between Minstrel & Minstrel_HT Minstrel and Mintrel_HT used there own structs to keep track of rate statistics. Unify those variables in struct minstrel_rate_states and move it to rc80211_minstrel.h for common usage. This is a clean-up patch to prepare Minstrel and Minstrel_HT codebase for upcoming TPC. Signed-off-by: Thomas Huehn Acked-by: Felix Fietkau Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 1c1469c..2baa7ed 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -75,7 +75,7 @@ minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) { int j = MAX_THR_RATES; - while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp) + while (j > 0 && mi->r[i].stats.cur_tp > mi->r[tp_list[j - 1]].stats.cur_tp) j--; if (j < MAX_THR_RATES - 1) memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); @@ -92,7 +92,7 @@ minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *rate ratetbl->rate[offset].idx = r->rix; ratetbl->rate[offset].count = r->adjusted_retry_count; ratetbl->rate[offset].count_cts = r->retry_count_cts; - ratetbl->rate[offset].count_rts = r->retry_count_rtscts; + ratetbl->rate[offset].count_rts = r->stats.retry_count_rtscts; } static void @@ -140,44 +140,46 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; + struct minstrel_rate_stats *mrs = &mi->r[i].stats; usecs = mr->perfect_tx_time; if (!usecs) usecs = 1000000; - if (unlikely(mr->attempts > 0)) { - mr->sample_skipped = 0; - mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); - mr->succ_hist += mr->success; - mr->att_hist += mr->attempts; - mr->probability = minstrel_ewma(mr->probability, - mr->cur_prob, - EWMA_LEVEL); + if (unlikely(mrs->attempts > 0)) { + mrs->sample_skipped = 0; + mrs->cur_prob = MINSTREL_FRAC(mrs->success, + mrs->attempts); + mrs->succ_hist += mrs->success; + mrs->att_hist += mrs->attempts; + mrs->probability = minstrel_ewma(mrs->probability, + mrs->cur_prob, + EWMA_LEVEL); } else - mr->sample_skipped++; + mrs->sample_skipped++; - mr->last_success = mr->success; - mr->last_attempts = mr->attempts; - mr->success = 0; - mr->attempts = 0; + mrs->last_success = mrs->success; + mrs->last_attempts = mrs->attempts; + mrs->success = 0; + mrs->attempts = 0; /* Update throughput per rate, reset thr. below 10% success */ - if (mr->probability < MINSTREL_FRAC(10, 100)) - mr->cur_tp = 0; + if (mrs->probability < MINSTREL_FRAC(10, 100)) + mrs->cur_tp = 0; else - mr->cur_tp = mr->probability * (1000000 / usecs); + mrs->cur_tp = mrs->probability * (1000000 / usecs); /* Sample less often below the 10% chance of success. * Sample less often above the 95% chance of success. */ - if (mr->probability > MINSTREL_FRAC(95, 100) || - mr->probability < MINSTREL_FRAC(10, 100)) { - mr->adjusted_retry_count = mr->retry_count >> 1; + if (mrs->probability > MINSTREL_FRAC(95, 100) || + mrs->probability < MINSTREL_FRAC(10, 100)) { + mr->adjusted_retry_count = mrs->retry_count >> 1; if (mr->adjusted_retry_count > 2) mr->adjusted_retry_count = 2; mr->sample_limit = 4; } else { mr->sample_limit = -1; - mr->adjusted_retry_count = mr->retry_count; + mr->adjusted_retry_count = mrs->retry_count; } if (!mr->adjusted_retry_count) mr->adjusted_retry_count = 2; @@ -190,11 +192,11 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) * choose the maximum throughput rate as max_prob_rate * (2) if all success probabilities < 95%, the rate with * highest success probability is choosen as max_prob_rate */ - if (mr->probability >= MINSTREL_FRAC(95, 100)) { - if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp) + if (mrs->probability >= MINSTREL_FRAC(95, 100)) { + if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) tmp_prob_rate = i; } else { - if (mr->probability >= mi->r[tmp_prob_rate].probability) + if (mrs->probability >= mi->r[tmp_prob_rate].stats.probability) tmp_prob_rate = i; } } @@ -240,14 +242,14 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, if (ndx < 0) continue; - mi->r[ndx].attempts += ar[i].count; + mi->r[ndx].stats.attempts += ar[i].count; if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) - mi->r[ndx].success += success; + mi->r[ndx].stats.success += success; } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) - mi->sample_count++; + mi->sample_packets++; if (mi->sample_deferred > 0) mi->sample_deferred--; @@ -265,7 +267,7 @@ minstrel_get_retry_count(struct minstrel_rate *mr, unsigned int retry = mr->adjusted_retry_count; if (info->control.use_rts) - retry = max(2U, min(mr->retry_count_rtscts, retry)); + retry = max(2U, min(mr->stats.retry_count_rtscts, retry)); else if (info->control.use_cts_prot) retry = max(2U, min(mr->retry_count_cts, retry)); return retry; @@ -317,15 +319,15 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, sampling_ratio = mp->lookaround_rate; /* increase sum packet counter */ - mi->packet_count++; + mi->total_packets++; #ifdef CONFIG_MAC80211_DEBUGFS if (mp->fixed_rate_idx != -1) return; #endif - delta = (mi->packet_count * sampling_ratio / 100) - - (mi->sample_count + mi->sample_deferred / 2); + delta = (mi->total_packets * sampling_ratio / 100) - + (mi->sample_packets + mi->sample_deferred / 2); /* delta < 0: no sampling required */ prev_sample = mi->prev_sample; @@ -333,10 +335,10 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, if (delta < 0 || (!mrr_capable && prev_sample)) return; - if (mi->packet_count >= 10000) { + if (mi->total_packets >= 10000) { mi->sample_deferred = 0; - mi->sample_count = 0; - mi->packet_count = 0; + mi->sample_packets = 0; + mi->total_packets = 0; } else if (delta > mi->n_rates * 2) { /* With multi-rate retry, not every planned sample * attempt actually gets used, due to the way the retry @@ -347,7 +349,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, * starts getting worse, minstrel would start bursting * out lots of sampling frames, which would result * in a large throughput loss. */ - mi->sample_count += (delta - mi->n_rates * 2); + mi->sample_packets += (delta - mi->n_rates * 2); } /* get next random rate sample */ @@ -361,7 +363,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, */ if (mrr_capable && msr->perfect_tx_time > mr->perfect_tx_time && - msr->sample_skipped < 20) { + msr->stats.sample_skipped < 20) { /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark * packets that have the sampling rate deferred to the * second MRR stage. Increase the sample counter only @@ -375,7 +377,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, if (!msr->sample_limit != 0) return; - mi->sample_count++; + mi->sample_packets++; if (msr->sample_limit > 0) msr->sample_limit--; } @@ -384,7 +386,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, * has a probability of >95%, we shouldn't be attempting * to use it, as this only wastes precious airtime */ if (!mrr_capable && - (mi->r[ndx].probability > MINSTREL_FRAC(95, 100))) + (mi->r[ndx].stats.probability > MINSTREL_FRAC(95, 100))) return; mi->prev_sample = true; @@ -459,6 +461,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, for (i = 0; i < sband->n_bitrates; i++) { struct minstrel_rate *mr = &mi->r[n]; + struct minstrel_rate_stats *mrs = &mi->r[n].stats; unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; unsigned int tx_time_single; unsigned int cw = mp->cw_min; @@ -471,6 +474,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, n++; memset(mr, 0, sizeof(*mr)); + memset(mrs, 0, sizeof(*mrs)); mr->rix = i; shift = ieee80211_chandef_get_shift(chandef); @@ -482,9 +486,9 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, /* calculate maximum number of retransmissions before * fallback (based on maximum segment size) */ mr->sample_limit = -1; - mr->retry_count = 1; + mrs->retry_count = 1; mr->retry_count_cts = 1; - mr->retry_count_rtscts = 1; + mrs->retry_count_rtscts = 1; tx_time = mr->perfect_tx_time + mi->sp_ack_dur; do { /* add one retransmission */ @@ -501,13 +505,13 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, (mr->retry_count_cts < mp->max_retry)) mr->retry_count_cts++; if ((tx_time_rtscts < mp->segment_size) && - (mr->retry_count_rtscts < mp->max_retry)) - mr->retry_count_rtscts++; + (mrs->retry_count_rtscts < mp->max_retry)) + mrs->retry_count_rtscts++; } while ((tx_time < mp->segment_size) && - (++mr->retry_count < mp->max_retry)); - mr->adjusted_retry_count = mr->retry_count; + (++mr->stats.retry_count < mp->max_retry)); + mr->adjusted_retry_count = mrs->retry_count; if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)) - mr->retry_count_cts = mr->retry_count; + mr->retry_count_cts = mrs->retry_count; } for (i = n; i < sband->n_bitrates; i++) { @@ -665,7 +669,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta) /* convert pkt per sec in kbps (1200 is the average pkt size used for * computing cur_tp */ - return MINSTREL_TRUNC(mi->r[idx].cur_tp) * 1200 * 8 / 1024; + return MINSTREL_TRUNC(mi->r[idx].stats.cur_tp) * 1200 * 8 / 1024; } const struct rate_control_ops mac80211_minstrel = { diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 046d1bd..97eca86 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -31,6 +31,27 @@ minstrel_ewma(int old, int new, int weight) return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV; } +struct minstrel_rate_stats { + /* current / last sampling period attempts/success counters */ + unsigned int attempts, last_attempts; + unsigned int success, last_success; + + /* total attempts/success counters */ + u64 att_hist, succ_hist; + + /* current throughput */ + unsigned int cur_tp; + + /* packet delivery probabilities */ + unsigned int cur_prob, probability; + + /* maximum retry counts */ + unsigned int retry_count; + unsigned int retry_count_rtscts; + + u8 sample_skipped; + bool retry_updated; +}; struct minstrel_rate { int bitrate; @@ -40,26 +61,10 @@ struct minstrel_rate { unsigned int ack_time; int sample_limit; - unsigned int retry_count; unsigned int retry_count_cts; - unsigned int retry_count_rtscts; unsigned int adjusted_retry_count; - u32 success; - u32 attempts; - u32 last_attempts; - u32 last_success; - u8 sample_skipped; - - /* parts per thousand */ - u32 cur_prob; - u32 probability; - - /* per-rate throughput */ - u32 cur_tp; - - u64 succ_hist; - u64 att_hist; + struct minstrel_rate_stats stats; }; struct minstrel_sta_info { @@ -73,8 +78,8 @@ struct minstrel_sta_info { u8 max_tp_rate[MAX_THR_RATES]; u8 max_prob_rate; - unsigned int packet_count; - unsigned int sample_count; + unsigned int total_packets; + unsigned int sample_packets; int sample_deferred; unsigned int sample_row; diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index fd0b9ca..edde723 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -72,6 +72,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) "this succ/attempt success attempts\n"); for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; + struct minstrel_rate_stats *mrs = &mi->r[i].stats; *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; @@ -81,24 +82,24 @@ minstrel_stats_open(struct inode *inode, struct file *file) p += sprintf(p, "%3u%s", mr->bitrate / 2, (mr->bitrate & 1 ? ".5" : " ")); - tp = MINSTREL_TRUNC(mr->cur_tp / 10); - prob = MINSTREL_TRUNC(mr->cur_prob * 1000); - eprob = MINSTREL_TRUNC(mr->probability * 1000); + tp = MINSTREL_TRUNC(mrs->cur_tp / 10); + prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); + eprob = MINSTREL_TRUNC(mrs->probability * 1000); p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " " %3u(%3u) %8llu %8llu\n", tp / 10, tp % 10, eprob / 10, eprob % 10, prob / 10, prob % 10, - mr->last_success, - mr->last_attempts, - (unsigned long long)mr->succ_hist, - (unsigned long long)mr->att_hist); + mrs->last_success, + mrs->last_attempts, + (unsigned long long)mrs->succ_hist, + (unsigned long long)mrs->att_hist); } p += sprintf(p, "\nTotal packet count:: ideal %d " "lookaround %d\n\n", - mi->packet_count - mi->sample_count, - mi->sample_count); + mi->total_packets - mi->sample_packets, + mi->sample_packets); ms->len = p - ms->buf; return 0; diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index d655586..5fee938 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -26,28 +26,6 @@ struct mcs_group { extern const struct mcs_group minstrel_mcs_groups[]; -struct minstrel_rate_stats { - /* current / last sampling period attempts/success counters */ - unsigned int attempts, last_attempts; - unsigned int success, last_success; - - /* total attempts/success counters */ - u64 att_hist, succ_hist; - - /* current throughput */ - unsigned int cur_tp; - - /* packet delivery probabilities */ - unsigned int cur_prob, probability; - - /* maximum retry counts */ - unsigned int retry_count; - unsigned int retry_count_rtscts; - - bool retry_updated; - u8 sample_skipped; -}; - struct minstrel_mcs_group_data { u8 index; u8 column; -- cgit v0.10.2 From 5935839ad73583781b8bbe8d91412f6826e218a4 Mon Sep 17 00:00:00 2001 From: Thomas Huehn Date: Tue, 9 Sep 2014 23:22:14 +0200 Subject: mac80211: improve minstrel_ht rate sorting by throughput & probability This patch improves the way minstrel_ht sorts rates according to throughput and success probability. 3 FOR-loops across the entire rate and mcs group set in function minstrel_ht_update_stats() which where used to determine the fastest, second fastest and most robust rate are reduced to 2 FOR-loop. The sorted list of rates according throughput is extended to the best four rates as we need them in upcoming joint rate and power control. The sorting is done via the new function minstrel_ht_sort_best_tp_rates(). The annotation of those 4 best throughput rates in the debugfs file rc-stats is changes to: "A,B,C,D", where A is the fastest rate and C the 4th fastest. Signed-off-by: Thomas Huehn Tested-by: Stefan Venz Acked-by: Felix Fietkau Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 85c1e74..df90ce2 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); static int minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) { - return GROUP_IDX((rate->idx / 8) + 1, + return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); } @@ -233,12 +233,151 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) } /* + * Find & sort topmost throughput rates + * + * If multiple rates provide equal throughput the sorting is based on their + * current success probability. Higher success probability is preferred among + * MCS groups, CCK rates do not provide aggregation and are therefore at last. + */ +static void +minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, + u8 *tp_list) +{ + int cur_group, cur_idx, cur_thr, cur_prob; + int tmp_group, tmp_idx, tmp_thr, tmp_prob; + int j = MAX_THR_RATES; + + cur_group = index / MCS_GROUP_RATES; + cur_idx = index % MCS_GROUP_RATES; + cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp; + cur_prob = mi->groups[cur_group].rates[cur_idx].probability; + + tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; + tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; + tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp; + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability; + + while (j > 0 && (cur_thr > tmp_thr || + (cur_thr == tmp_thr && cur_prob > tmp_prob))) { + j--; + tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; + tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; + tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp; + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability; + } + + if (j < MAX_THR_RATES - 1) { + memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) * + (MAX_THR_RATES - (j + 1)))); + } + if (j < MAX_THR_RATES) + tp_list[j] = index; +} + +/* + * Find and set the topmost probability rate per sta and per group + */ +static void +minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) +{ + struct minstrel_mcs_group_data *mg; + struct minstrel_rate_stats *mr; + int tmp_group, tmp_idx, tmp_tp, tmp_prob, max_tp_group; + + mg = &mi->groups[index / MCS_GROUP_RATES]; + mr = &mg->rates[index % MCS_GROUP_RATES]; + + tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; + tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; + tmp_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability; + + /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from + * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ + max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; + if((index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) && + (max_tp_group != MINSTREL_CCK_GROUP)) + return; + + if (mr->probability > MINSTREL_FRAC(75, 100)) { + if (mr->cur_tp > tmp_tp) + mi->max_prob_rate = index; + if (mr->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp) + mg->max_group_prob_rate = index; + } else { + if (mr->probability > tmp_prob) + mi->max_prob_rate = index; + if (mr->probability > mg->rates[mg->max_group_prob_rate].probability) + mg->max_group_prob_rate = index; + } +} + + +/* + * Assign new rate set per sta and use CCK rates only if the fastest + * rate (max_tp_rate[0]) is from CCK group. This prohibits such sorted + * rate sets where MCS and CCK rates are mixed, because CCK rates can + * not use aggregation. + */ +static void +minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, + u8 tmp_mcs_tp_rate[MAX_THR_RATES], + u8 tmp_cck_tp_rate[MAX_THR_RATES]) +{ + unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; + int i; + + tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; + tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; + tmp_cck_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; + + tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; + tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; + tmp_mcs_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; + + if (tmp_cck_tp > tmp_mcs_tp) { + for(i = 0; i < MAX_THR_RATES; i++) { + minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i], + tmp_mcs_tp_rate); + } + } + +} + +/* + * Try to increase robustness of max_prob rate by decrease number of + * streams if possible. + */ +static inline void +minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) +{ + struct minstrel_mcs_group_data *mg; + struct minstrel_rate_stats *mr; + int tmp_max_streams, group; + int tmp_tp = 0; + + tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / + MCS_GROUP_RATES].streams; + for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { + mg = &mi->groups[group]; + if (!mg->supported || group == MINSTREL_CCK_GROUP) + continue; + mr = minstrel_get_ratestats(mi, mg->max_group_prob_rate); + if (tmp_tp < mr->cur_tp && + (minstrel_mcs_groups[group].streams < tmp_max_streams)) { + mi->max_prob_rate = mg->max_group_prob_rate; + tmp_tp = mr->cur_tp; + } + } +} + +/* * Update rate statistics and select new primary rates * * Rules for rate selection: * - max_prob_rate must use only one stream, as a tradeoff between delivery * probability and throughput during strong fluctuations - * - as long as the max prob rate has a probability of more than 3/4, pick + * - as long as the max prob rate has a probability of more than 75%, pick * higher throughput rates, even if the probablity is a bit lower */ static void @@ -246,9 +385,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { struct minstrel_mcs_group_data *mg; struct minstrel_rate_stats *mr; - int cur_prob, cur_prob_tp, cur_tp, cur_tp2; - int group, i, index; - bool mi_rates_valid = false; + int group, i, j; + u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; + u8 tmp_cck_tp_rate[MAX_THR_RATES], index; if (mi->ampdu_packets > 0) { mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, @@ -260,13 +399,14 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) mi->sample_slow = 0; mi->sample_count = 0; - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { - bool mg_rates_valid = false; + /* Initialize global rate indexes */ + for(j = 0; j < MAX_THR_RATES; j++){ + tmp_mcs_tp_rate[j] = 0; + tmp_cck_tp_rate[j] = 0; + } - cur_prob = 0; - cur_prob_tp = 0; - cur_tp = 0; - cur_tp2 = 0; + /* Find best rate sets within all MCS groups*/ + for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { mg = &mi->groups[group]; if (!mg->supported) @@ -274,24 +414,16 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) mi->sample_count++; + /* (re)Initialize group rate indexes */ + for(j = 0; j < MAX_THR_RATES; j++) + tmp_group_tp_rate[j] = group; + for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mg->supported & BIT(i))) continue; index = MCS_GROUP_RATES * group + i; - /* initialize rates selections starting indexes */ - if (!mg_rates_valid) { - mg->max_tp_rate = mg->max_tp_rate2 = - mg->max_prob_rate = i; - if (!mi_rates_valid) { - mi->max_tp_rate = mi->max_tp_rate2 = - mi->max_prob_rate = index; - mi_rates_valid = true; - } - mg_rates_valid = true; - } - mr = &mg->rates[i]; mr->retry_updated = false; minstrel_calc_rate_ewma(mr); @@ -300,82 +432,47 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) if (!mr->cur_tp) continue; - if ((mr->cur_tp > cur_prob_tp && mr->probability > - MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { - mg->max_prob_rate = index; - cur_prob = mr->probability; - cur_prob_tp = mr->cur_tp; - } - - if (mr->cur_tp > cur_tp) { - swap(index, mg->max_tp_rate); - cur_tp = mr->cur_tp; - mr = minstrel_get_ratestats(mi, index); - } - - if (index >= mg->max_tp_rate) - continue; - - if (mr->cur_tp > cur_tp2) { - mg->max_tp_rate2 = index; - cur_tp2 = mr->cur_tp; + /* Find max throughput rate set */ + if (group != MINSTREL_CCK_GROUP) { + minstrel_ht_sort_best_tp_rates(mi, index, + tmp_mcs_tp_rate); + } else if (group == MINSTREL_CCK_GROUP) { + minstrel_ht_sort_best_tp_rates(mi, index, + tmp_cck_tp_rate); } - } - } - /* try to sample all available rates during each interval */ - mi->sample_count *= 8; + /* Find max throughput rate set within a group */ + minstrel_ht_sort_best_tp_rates(mi, index, + tmp_group_tp_rate); - cur_prob = 0; - cur_prob_tp = 0; - cur_tp = 0; - cur_tp2 = 0; - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { - mg = &mi->groups[group]; - if (!mg->supported) - continue; - - mr = minstrel_get_ratestats(mi, mg->max_tp_rate); - if (cur_tp < mr->cur_tp) { - mi->max_tp_rate2 = mi->max_tp_rate; - cur_tp2 = cur_tp; - mi->max_tp_rate = mg->max_tp_rate; - cur_tp = mr->cur_tp; - mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1; + /* Find max probability rate per group and global */ + minstrel_ht_set_best_prob_rate(mi, index); } - mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); - if (cur_tp2 < mr->cur_tp) { - mi->max_tp_rate2 = mg->max_tp_rate2; - cur_tp2 = mr->cur_tp; - } + memcpy(mg->max_group_tp_rate, tmp_group_tp_rate, + sizeof(mg->max_group_tp_rate)); } - if (mi->max_prob_streams < 1) - mi->max_prob_streams = 1; + /* Assign new rate set per sta */ + minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate); + memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate)); - for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { - mg = &mi->groups[group]; - if (!mg->supported) - continue; - mr = minstrel_get_ratestats(mi, mg->max_prob_rate); - if (cur_prob_tp < mr->cur_tp && - minstrel_mcs_groups[group].streams <= mi->max_prob_streams) { - mi->max_prob_rate = mg->max_prob_rate; - cur_prob = mr->cur_prob; - cur_prob_tp = mr->cur_tp; - } - } + /* Try to increase robustness of max_prob_rate*/ + minstrel_ht_prob_rate_reduce_streams(mi); + + /* try to sample all available rates during each interval */ + mi->sample_count *= 8; #ifdef CONFIG_MAC80211_DEBUGFS /* use fixed index if set */ if (mp->fixed_rate_idx != -1) { - mi->max_tp_rate = mp->fixed_rate_idx; - mi->max_tp_rate2 = mp->fixed_rate_idx; + for (i = 0; i < 4; i++) + mi->max_tp_rate[i] = mp->fixed_rate_idx; mi->max_prob_rate = mp->fixed_rate_idx; } #endif + /* Reset update timer */ mi->stats_update = jiffies; } @@ -420,8 +517,7 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi) } static void -minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx, - bool primary) +minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary) { int group, orig_group; @@ -437,9 +533,9 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx, continue; if (primary) - *idx = mi->groups[group].max_tp_rate; + *idx = mi->groups[group].max_group_tp_rate[0]; else - *idx = mi->groups[group].max_tp_rate2; + *idx = mi->groups[group].max_group_tp_rate[1]; break; } } @@ -524,19 +620,19 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, * check for sudden death of spatial multiplexing, * downgrade to a lower number of streams if necessary. */ - rate = minstrel_get_ratestats(mi, mi->max_tp_rate); + rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); if (rate->attempts > 30 && MINSTREL_FRAC(rate->success, rate->attempts) < MINSTREL_FRAC(20, 100)) { - minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); + minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); update = true; } - rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); + rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); if (rate2->attempts > 30 && MINSTREL_FRAC(rate2->success, rate2->attempts) < MINSTREL_FRAC(20, 100)) { - minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); + minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); update = true; } @@ -661,12 +757,12 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) if (!rates) return; - /* Start with max_tp_rate */ - minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate); + /* Start with max_tp_rate[0] */ + minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]); if (mp->hw->max_rates >= 3) { - /* At least 3 tx rates supported, use max_tp_rate2 next */ - minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate2); + /* At least 3 tx rates supported, use max_tp_rate[1] next */ + minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[1]); } if (mp->hw->max_rates >= 2) { @@ -691,7 +787,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { struct minstrel_rate_stats *mr; struct minstrel_mcs_group_data *mg; - unsigned int sample_dur, sample_group; + unsigned int sample_dur, sample_group, cur_max_tp_streams; int sample_idx = 0; if (mi->sample_wait > 0) { @@ -718,8 +814,8 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) * to the frame. Hence, don't use sampling for the currently * used rates. */ - if (sample_idx == mi->max_tp_rate || - sample_idx == mi->max_tp_rate2 || + if (sample_idx == mi->max_tp_rate[0] || + sample_idx == mi->max_tp_rate[1] || sample_idx == mi->max_prob_rate) return -1; @@ -734,9 +830,12 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) * Make sure that lower rates get sampled only occasionally, * if the link is working perfectly. */ + + cur_max_tp_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / + MCS_GROUP_RATES].streams; sample_dur = minstrel_get_duration(sample_idx); - if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) && - (mi->max_prob_streams < + if (sample_dur >= minstrel_get_duration(mi->max_tp_rate[1]) && + (cur_max_tp_streams - 1 < minstrel_mcs_groups[sample_group].streams || sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { if (mr->sample_skipped < 20) @@ -1041,8 +1140,8 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) if (!msp->is_ht) return mac80211_minstrel.get_expected_throughput(priv_sta); - i = mi->max_tp_rate / MCS_GROUP_RATES; - j = mi->max_tp_rate % MCS_GROUP_RATES; + i = mi->max_tp_rate[0] / MCS_GROUP_RATES; + j = mi->max_tp_rate[0] % MCS_GROUP_RATES; /* convert cur_tp from pkt per second in kbps */ return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024; diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 5fee938..01570e0 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h @@ -33,10 +33,9 @@ struct minstrel_mcs_group_data { /* bitfield of supported MCS rates of this group */ u8 supported; - /* selected primary rates */ - unsigned int max_tp_rate; - unsigned int max_tp_rate2; - unsigned int max_prob_rate; + /* sorted rate set within a MCS group*/ + u8 max_group_tp_rate[MAX_THR_RATES]; + u8 max_group_prob_rate; /* MCS rate statistics */ struct minstrel_rate_stats rates[MCS_GROUP_RATES]; @@ -52,15 +51,9 @@ struct minstrel_ht_sta { /* ampdu length (EWMA) */ unsigned int avg_ampdu_len; - /* best throughput rate */ - unsigned int max_tp_rate; - - /* second best throughput rate */ - unsigned int max_tp_rate2; - - /* best probability rate */ - unsigned int max_prob_rate; - unsigned int max_prob_streams; + /* overall sorted rate set */ + u8 max_tp_rate[MAX_THR_RATES]; + u8 max_prob_rate; /* time of last status update */ unsigned long stats_update; diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 3e7d793..a72ad46 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -46,8 +46,10 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) else p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); - *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' '; - *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' '; + *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; + *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; + *(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' '; + *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; if (i == max_mcs) { @@ -100,8 +102,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) file->private_data = ms; p = ms->buf; - p += sprintf(p, "type rate throughput ewma prob this prob " - "retry this succ/attempt success attempts\n"); + p += sprintf(p, "type rate throughput ewma prob " + "this prob retry this succ/attempt success attempts\n"); p = minstrel_ht_stats_dump(mi, max_mcs, p); for (i = 0; i < max_mcs; i++) -- cgit v0.10.2 From 9d58f25b12f70f52581a5a1fdb1e59d322c4c729 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Thu, 4 Sep 2014 08:28:40 +0300 Subject: mac80211: add TDLS connection timeout Adding a timeout for tearing down a TDLS connection that hasn't had ACKed traffic sent through it for a certain amount of time. Since we have no other monitoring facility to indicate the existance (or non-existance) of a peer, this patch will cause a peer to be considered as unavailable if for some X time at least some Y packets have all not been ACKed. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9dc7a9d..42f68cb 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -450,6 +450,9 @@ struct sta_info { enum ieee80211_smps_mode known_smps_mode; const struct ieee80211_cipher_scheme *cipher_scheme; + /* TDLS timeout data */ + unsigned long last_tdls_pkt_time; + /* keep last! */ struct ieee80211_sta sta; }; diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2800e1c..89290e3 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -538,6 +538,8 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, * - current throughput (higher value for higher tpt)? */ #define STA_LOST_PKT_THRESHOLD 50 +#define STA_LOST_TDLS_PKT_THRESHOLD 10 +#define STA_LOST_TDLS_PKT_TIME (10*HZ) /* 10secs since last ACK */ static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) { @@ -548,7 +550,20 @@ static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD) + sta->lost_packets++; + if (!sta->sta.tdls && sta->lost_packets < STA_LOST_PKT_THRESHOLD) + return; + + /* + * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD + * of the last packets were lost, and that no ACK was received in the + * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss + * mechanism. + */ + if (sta->sta.tdls && + (sta->lost_packets < STA_LOST_TDLS_PKT_THRESHOLD || + time_before(jiffies, + sta->last_tdls_pkt_time + STA_LOST_TDLS_PKT_TIME))) return; cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, @@ -695,6 +710,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_STAT_ACK) { if (sta->lost_packets) sta->lost_packets = 0; + + /* Track when last TDLS packet was ACKed */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) + sta->last_tdls_pkt_time = jiffies; } else { ieee80211_lost_packet(sta, skb); } -- cgit v0.10.2 From 960d01acf62747d6518694f92be5b06f67473833 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Sep 2014 22:55:35 +0300 Subject: cfg80211: add WMM traffic stream API Add nl80211 and driver API to validate, add and delete traffic streams with appropriate settings. The API calls for userspace doing the action frame handshake with the peer, and then allows only to set up the parameters in the driver. To avoid setting up a session only to tear it down again, the validate API is provided, but the real usage later can still fail so userspace must be prepared for that. Signed-off-by: Johannes Berg diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 61a09f0..b1be39c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -166,8 +166,12 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) #define IEEE80211_MAX_MESH_ID_LEN 32 +#define IEEE80211_FIRST_TSPEC_TSID 8 #define IEEE80211_NUM_TIDS 16 +/* number of user priorities 802.11 uses */ +#define IEEE80211_NUM_UPS 8 + #define IEEE80211_QOS_CTL_LEN 2 /* 1d tag mask */ #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c2c710c..a13beab1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2318,6 +2318,17 @@ struct cfg80211_qos_map { * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the * given interface This is used e.g. for dynamic HT 20/40 MHz channel width * changes during the lifetime of the BSS. + * + * @add_tx_ts: validate (if admitted_time is 0) or add a TX TS to the device + * with the given parameters; action frame exchange has been handled by + * userspace so this just has to modify the TX path to take the TS into + * account. + * If the admitted time is 0 just validate the parameters to make sure + * the session can be created at all; it is valid to just always return + * success for that but that may result in inefficient behaviour (handshake + * with the peer followed by immediate teardown when the addition is later + * rejected) + * @del_tx_ts: remove an existing TX TS */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -2558,6 +2569,12 @@ struct cfg80211_ops { int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_chan_def *chandef); + + int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev, + u8 tsid, const u8 *peer, u8 user_prio, + u16 admitted_time); + int (*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev, + u8 tsid, const u8 *peer); }; /* @@ -2604,9 +2621,13 @@ struct cfg80211_ops { * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in * beaconing mode (AP, IBSS, Mesh, ...). + * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM + * TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS + * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it + * needs to be able to handle Block-Ack agreements and other things. */ enum wiphy_flags { - /* use hole at 0 */ + WIPHY_FLAG_SUPPORTS_WMM_ADMISSION = BIT(0), /* use hole at 1 */ /* use hole at 2 */ WIPHY_FLAG_NETNS_OK = BIT(3), diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 29c4399..e5b8caf 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -722,6 +722,22 @@ * QoS mapping is relevant for IP packets, it is only valid during an * association. This is cleared on disassociation and AP restart. * + * @NL80211_CMD_ADD_TX_TS: Ask the kernel to add a traffic stream for the given + * %NL80211_ATTR_TSID and %NL80211_ATTR_MAC with %NL80211_ATTR_USER_PRIO + * and %NL80211_ATTR_ADMITTED_TIME parameters. + * Note that the action frame handshake with the AP shall be handled by + * userspace via the normal management RX/TX framework, this only sets + * up the TX TS in the driver/device. + * If the admitted time attribute is not added then the request just checks + * if a subsequent setup could be successful, the intent is to use this to + * avoid setting up a session with the AP when local restrictions would + * make that impossible. However, the subsequent "real" setup may still + * fail even if the check was successful. + * @NL80211_CMD_DEL_TX_TS: Remove an existing TS with the %NL80211_ATTR_TSID + * and %NL80211_ATTR_MAC parameters. It isn't necessary to call this + * before removing a station entry entirely, or before disassociating + * or similar, cleanup will happen in the driver/device in this case. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -893,6 +909,9 @@ enum nl80211_commands { NL80211_CMD_SET_QOS_MAP, + NL80211_CMD_ADD_TX_TS, + NL80211_CMD_DEL_TX_TS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1611,6 +1630,11 @@ enum nl80211_commands { * drivers to indicate dynack capability. Dynack is automatically disabled * setting valid value for coverage class. * + * @NL80211_ATTR_TSID: a TSID value (u8 attribute) + * @NL80211_ATTR_USER_PRIO: user priority value (u8 attribute) + * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds + * (per second) (u16 attribute) + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1957,6 +1981,10 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_DYN_ACK, + NL80211_ATTR_TSID, + NL80211_ATTR_USER_PRIO, + NL80211_ATTR_ADMITTED_TIME, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e9fbd4f..ab7ee48 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -391,6 +391,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG }, + [NL80211_ATTR_TSID] = { .type = NLA_U8 }, + [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, + [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, }; /* policy for the key attributes */ @@ -1510,6 +1513,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) CMD(channel_switch, CHANNEL_SWITCH); CMD(set_qos_map, SET_QOS_MAP); + if (rdev->wiphy.flags & + WIPHY_FLAG_SUPPORTS_WMM_ADMISSION) + CMD(add_tx_ts, ADD_TX_TS); } /* add into the if now */ #undef CMD @@ -9390,6 +9396,93 @@ static int nl80211_set_qos_map(struct sk_buff *skb, return ret; } +static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + const u8 *peer; + u8 tsid, up; + u16 admitted_time = 0; + int err; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] || + !info->attrs[NL80211_ATTR_USER_PRIO]) + return -EINVAL; + + tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]); + if (tsid >= IEEE80211_NUM_TIDS) + return -EINVAL; + + up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]); + if (up >= IEEE80211_NUM_UPS) + return -EINVAL; + + /* WMM uses TIDs 0-7 even for TSPEC */ + if (tsid < IEEE80211_FIRST_TSPEC_TSID) { + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) + return -EINVAL; + } else { + /* TODO: handle 802.11 TSPEC/admission control + * need more attributes for that (e.g. BA session requirement) + */ + return -EINVAL; + } + + peer = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) { + admitted_time = + nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]); + if (!admitted_time) + return -EINVAL; + } + + wdev_lock(wdev); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->current_bss) + break; + err = -ENOTCONN; + goto out; + default: + err = -EOPNOTSUPP; + goto out; + } + + err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time); + + out: + wdev_unlock(wdev); + return err; +} + +static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + const u8 *peer; + u8 tsid; + int err; + + if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]); + peer = nla_data(info->attrs[NL80211_ATTR_MAC]); + + wdev_lock(wdev); + err = rdev_del_tx_ts(rdev, dev, tsid, peer); + wdev_unlock(wdev); + + return err; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -10147,6 +10240,22 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_ADD_TX_TS, + .doit = nl80211_add_tx_ts, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_DEL_TX_TS, + .doit = nl80211_del_tx_ts, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; /* notification functions */ diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 56c2240..f6d457d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -915,4 +915,35 @@ rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_add_tx_ts(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 tsid, const u8 *peer, + u8 user_prio, u16 admitted_time) +{ + int ret = -EOPNOTSUPP; + + trace_rdev_add_tx_ts(&rdev->wiphy, dev, tsid, peer, + user_prio, admitted_time); + if (rdev->ops->add_tx_ts) + ret = rdev->ops->add_tx_ts(&rdev->wiphy, dev, tsid, peer, + user_prio, admitted_time); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + +static inline int +rdev_del_tx_ts(struct cfg80211_registered_device *rdev, + struct net_device *dev, u8 tsid, const u8 *peer) +{ + int ret = -EOPNOTSUPP; + + trace_rdev_del_tx_ts(&rdev->wiphy, dev, tsid, peer); + if (rdev->ops->del_tx_ts) + ret = rdev->ops->del_tx_ts(&rdev->wiphy, dev, tsid, peer); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 0c524cd..625a6e6 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1896,6 +1896,51 @@ TRACE_EVENT(rdev_set_ap_chanwidth, WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG) ); +TRACE_EVENT(rdev_add_tx_ts, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u8 tsid, const u8 *peer, u8 user_prio, u16 admitted_time), + TP_ARGS(wiphy, netdev, tsid, peer, user_prio, admitted_time), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(u8, tsid) + __field(u8, user_prio) + __field(u16, admitted_time) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->tsid = tsid; + __entry->user_prio = user_prio; + __entry->admitted_time = admitted_time; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d, UP %d, time %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), + __entry->tsid, __entry->user_prio, __entry->admitted_time) +); + +TRACE_EVENT(rdev_del_tx_ts, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + u8 tsid, const u8 *peer), + TP_ARGS(wiphy, netdev, tsid, peer), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + MAC_ENTRY(peer) + __field(u8, tsid) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + MAC_ASSIGN(peer, peer); + __entry->tsid = tsid; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ -- cgit v0.10.2 From b0b6aa2c8e0d0e34f7658d5cc1e4fbb59f701c42 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 9 Sep 2014 17:09:45 +0300 Subject: cfg80211/mac80211: add wmm info to assoc event Userspace might need to know what queues are configured for uapsd (e.g. for setting proper default values in tspecs). Add this bitmap to the association event (inside wmm nested attribute) Add additional parameter to cfg80211_rx_assoc_resp, and update its callers. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a13beab1..2ed1f80 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3944,6 +3944,7 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr); * moves to cfg80211 in this call * @buf: authentication frame (header + body) * @len: length of the frame data + * @uapsd_queues: bitmap of ACs configured to uapsd. -1 if n/a. * * After being asked to associate via cfg80211_ops::assoc() the driver must * call either this function or cfg80211_auth_timeout(). @@ -3952,7 +3953,8 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr); */ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, - const u8 *buf, size_t len); + const u8 *buf, size_t len, + int uapsd_queues); /** * cfg80211_assoc_timeout - notification of timed out association diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a7b92f5..efa41fc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2817,6 +2817,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; + int ac, uapsd_queues = -1; u8 *pos; bool reassoc; struct cfg80211_bss *bss; @@ -2886,9 +2887,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * is set can cause the interface to go idle */ ieee80211_destroy_assoc_data(sdata, true); + + /* get uapsd queues configuration */ + uapsd_queues = 0; + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + if (sdata->tx_conf[ac].uapsd) + uapsd_queues |= BIT(ac); } - cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len); + cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues); } static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 369fc33..2c52b59 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -19,7 +19,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, - const u8 *buf, size_t len) + const u8 *buf, size_t len, int uapsd_queues) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; @@ -43,7 +43,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, return; } - nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); + nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues); /* update current_bss etc., consumes the bss reference */ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab7ee48..e8114c7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10524,7 +10524,8 @@ nla_put_failure: static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, - enum nl80211_commands cmd, gfp_t gfp) + enum nl80211_commands cmd, gfp_t gfp, + int uapsd_queues) { struct sk_buff *msg; void *hdr; @@ -10544,6 +10545,19 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, nla_put(msg, NL80211_ATTR_FRAME, len, buf)) goto nla_put_failure; + if (uapsd_queues >= 0) { + struct nlattr *nla_wmm = + nla_nest_start(msg, NL80211_ATTR_STA_WME); + if (!nla_wmm) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES, + uapsd_queues)) + goto nla_put_failure; + + nla_nest_end(msg, nla_wmm); + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, @@ -10560,15 +10574,15 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_AUTHENTICATE, gfp); + NL80211_CMD_AUTHENTICATE, gfp, -1); } void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, - size_t len, gfp_t gfp) + size_t len, gfp_t gfp, int uapsd_queues) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_ASSOCIATE, gfp); + NL80211_CMD_ASSOCIATE, gfp, uapsd_queues); } void nl80211_send_deauth(struct cfg80211_registered_device *rdev, @@ -10576,7 +10590,7 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev, size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DEAUTHENTICATE, gfp); + NL80211_CMD_DEAUTHENTICATE, gfp, -1); } void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, @@ -10584,7 +10598,7 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, size_t len, gfp_t gfp) { nl80211_send_mlme_event(rdev, netdev, buf, len, - NL80211_CMD_DISASSOCIATE, gfp); + NL80211_CMD_DISASSOCIATE, gfp, -1); } void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, @@ -10605,7 +10619,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, cmd = NL80211_CMD_UNPROT_DISASSOCIATE; trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); - nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC); + nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1); } EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 49c9a48..7ad70d6 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -23,7 +23,8 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, struct net_device *netdev, - const u8 *buf, size_t len, gfp_t gfp); + const u8 *buf, size_t len, gfp_t gfp, + int uapsd_queues); void nl80211_send_deauth(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *buf, size_t len, gfp_t gfp); -- cgit v0.10.2 From 59cd85cbcf2ecca9736652dc0cfd2ec600d7ef2a Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 9 Sep 2014 17:11:02 +0300 Subject: mac80211: set network header in TDLS frames Correctly mark the network header location in mac80211-generated TDLS frames. These may be used by lower-level drivers. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Johannes Berg diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index bcf51e4..4ea25de 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -412,6 +412,9 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->ether_type = cpu_to_be16(ETH_P_TDLS); tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; + /* network header is after the ethernet header */ + skb_set_network_header(skb, ETH_HLEN); + switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: tf->category = WLAN_CATEGORY_TDLS; -- cgit v0.10.2 From 18998c381b19bfc3c285361ff6200ded7444aa2c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 10 Sep 2014 14:07:34 +0300 Subject: cfg80211: allow requesting SMPS mode on ap start Add feature bits to indicate device support for static-smps and dynamic-smps modes. Add a new NL80211_ATTR_SMPS_MODE attribue to allow configuring the smps mode to be used by the ap (e.g. configuring to ap to dynamic smps mode will reduce power consumption while having minor effect on throughput) Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2ed1f80..a2ddcf2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -664,6 +664,7 @@ struct cfg80211_acl_data { * @crypto: crypto settings * @privacy: the BSS uses privacy * @auth_type: Authentication type (algorithm) + * @smps_mode: SMPS mode * @inactivity_timeout: time in seconds to determine station's inactivity. * @p2p_ctwindow: P2P CT Window * @p2p_opp_ps: P2P opportunistic PS @@ -682,6 +683,7 @@ struct cfg80211_ap_settings { struct cfg80211_crypto_settings crypto; bool privacy; enum nl80211_auth_type auth_type; + enum nl80211_smps_mode smps_mode; int inactivity_timeout; u8 p2p_ctwindow; bool p2p_opp_ps; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e5b8caf..4b28dc0 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1635,6 +1635,9 @@ enum nl80211_commands { * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds * (per second) (u16 attribute) * + * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see + * &enum nl80211_smps_mode. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1985,6 +1988,8 @@ enum nl80211_attrs { NL80211_ATTR_USER_PRIO, NL80211_ATTR_ADMITTED_TIME, + NL80211_ATTR_SMPS_MODE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4030,6 +4035,13 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_ACKTO_ESTIMATION: This driver supports dynamic ACK timeout * estimation (dynack). %NL80211_ATTR_WIPHY_DYN_ACK flag attribute is used * to enable dynack. + * @NL80211_FEATURE_STATIC_SMPS: Device supports static spatial + * multiplexing powersave, ie. can turn off all but one chain + * even on HT connections that should be using more chains. + * @NL80211_FEATURE_DYNAMIC_SMPS: Device supports dynamic spatial + * multiplexing powersave, ie. can turn off all but one chain + * and then wake the rest up as required after, for example, + * rts/cts handshake. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, @@ -4056,6 +4068,8 @@ enum nl80211_feature_flags { NL80211_FEATURE_QUIET = 1 << 21, NL80211_FEATURE_TX_POWER_INSERTION = 1 << 22, NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23, + NL80211_FEATURE_STATIC_SMPS = 1 << 24, + NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, }; /** @@ -4130,6 +4144,25 @@ enum nl80211_acl_policy { }; /** + * enum nl80211_smps_mode - SMPS mode + * + * Requested SMPS mode (for AP mode) + * + * @NL80211_SMPS_OFF: SMPS off (use all antennas). + * @NL80211_SMPS_STATIC: static SMPS (use a single antenna) + * @NL80211_SMPS_DYNAMIC: dynamic smps (start with a single antenna and + * turn on other antennas after CTS/RTS). + */ +enum nl80211_smps_mode { + NL80211_SMPS_OFF, + NL80211_SMPS_STATIC, + NL80211_SMPS_DYNAMIC, + + __NL80211_SMPS_AFTER_LAST, + NL80211_SMPS_MAX = __NL80211_SMPS_AFTER_LAST - 1 +}; + +/** * enum nl80211_radar_event - type of radar event for DFS operation * * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e8114c7..4cce3e1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -394,6 +394,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_TSID] = { .type = NLA_U8 }, [NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 }, [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, + [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, }; /* policy for the key attributes */ @@ -3345,6 +3346,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) return PTR_ERR(params.acl); } + if (info->attrs[NL80211_ATTR_SMPS_MODE]) { + params.smps_mode = + nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]); + switch (params.smps_mode) { + case NL80211_SMPS_OFF: + break; + case NL80211_SMPS_STATIC: + if (!(rdev->wiphy.features & + NL80211_FEATURE_STATIC_SMPS)) + return -EINVAL; + break; + case NL80211_SMPS_DYNAMIC: + if (!(rdev->wiphy.features & + NL80211_FEATURE_DYNAMIC_SMPS)) + return -EINVAL; + break; + default: + return -EINVAL; + } + } else { + params.smps_mode = NL80211_SMPS_OFF; + } + wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { -- cgit v0.10.2 From f69931748730763f8c8095fa88394cf9af75a578 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 10 Sep 2014 14:07:35 +0300 Subject: mac80211: set smps_mode according to ap params Take the requested smps mode from the ap params (instead of always starting with SMPS_OFF) Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 101ae6c..fb6a150 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -683,8 +683,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (old) return -EALREADY; - /* TODO: make hostapd tell us what it wants */ - sdata->smps_mode = IEEE80211_SMPS_OFF; + switch (params->smps_mode) { + case NL80211_SMPS_OFF: + sdata->smps_mode = IEEE80211_SMPS_OFF; + break; + case NL80211_SMPS_STATIC: + sdata->smps_mode = IEEE80211_SMPS_STATIC; + break; + case NL80211_SMPS_DYNAMIC: + sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; + break; + default: + return -EINVAL; + } sdata->needed_rx_chains = sdata->local->rx_chains; mutex_lock(&local->mtx); -- cgit v0.10.2 From 0d8614b4b926d0f657d15d7eb5125bcb24b9fd41 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 10 Sep 2014 14:07:36 +0300 Subject: mac80211: replace SMPS hw flags with wiphy feature bits Use the new static_smps / dynamic_smps feature bits instead of mac80211-internal hw flags. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9d61bb1..4b5f001 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4759,7 +4759,6 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | IEEE80211_HW_AP_LINK_PS | IEEE80211_HW_SPECTRUM_MGMT; @@ -4767,8 +4766,10 @@ int ath10k_mac_register(struct ath10k *ar) * bytes is used for padding/alignment if necessary. */ ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; + ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; + if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) - ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; + ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) { ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 3dcbe2c..9f930a0 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5757,9 +5757,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (il->cfg->sku & IL_SKU_N) - hw->flags |= - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; hw->sta_data_size = sizeof(struct il_station_priv); hw->vif_data_size = sizeof(struct il_vif_priv); diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index afb98f4..2364a3c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -125,8 +125,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, */ if (priv->nvm_data->sku_cap_11n_enable) - hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; /* * Enable 11w if advertised by firmware and software crypto diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7c87965..395fc05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -301,9 +301,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TIMING_BEACON_ONLY | IEEE80211_HW_CONNECTION_MONITOR | - IEEE80211_HW_CHANCTX_STA_CSA | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_SUPPORTS_STATIC_SMPS; + IEEE80211_HW_CHANCTX_STA_CSA; hw->queues = mvm->first_agg_queue; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; @@ -405,7 +403,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | NL80211_FEATURE_LOW_PRIORITY_SCAN | - NL80211_FEATURE_P2P_GO_OPPPS; + NL80211_FEATURE_P2P_GO_OPPPS | + NL80211_FEATURE_DYNAMIC_SMPS | + NL80211_FEATURE_STATIC_SMPS; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1326f61..babbdc1 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2045,8 +2045,6 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, hw->flags = IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_WANT_MONITOR_VIF | IEEE80211_HW_QUEUE_CONTROL | @@ -2059,8 +2057,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_CHANNEL_SWITCH; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_STATIC_SMPS | + NL80211_FEATURE_DYNAMIC_SMPS; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c6e6a68..0ad1f47 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1537,16 +1537,6 @@ struct ieee80211_tx_control { * @IEEE80211_HW_MFP_CAPABLE: * Hardware supports management frame protection (MFP, IEEE 802.11w). * - * @IEEE80211_HW_SUPPORTS_STATIC_SMPS: - * Hardware supports static spatial multiplexing powersave, - * ie. can turn off all but one chain even on HT connections - * that should be using more chains. - * - * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS: - * Hardware supports dynamic spatial multiplexing powersave, - * ie. can turn off all but one chain and then wake the rest - * up as required after, for example, rts/cts handshake. - * * @IEEE80211_HW_SUPPORTS_UAPSD: * Hardware supports Unscheduled Automatic Power Save Delivery * (U-APSD) in managed mode. The mode is configured with @@ -1632,8 +1622,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12, IEEE80211_HW_MFP_CAPABLE = 1<<13, IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, - IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, + /* free slots */ IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, IEEE80211_HW_CONNECTION_MONITOR = 1<<19, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 5746561..54a189f 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -303,11 +303,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); - if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) - sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) - sf += scnprintf(buf + sf, mxln - sf, - "SUPPORTS_DYNAMIC_SMPS\n"); if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e205eba..c68896a 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -226,12 +226,12 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; int err; - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) && + if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) && smps_mode == IEEE80211_SMPS_STATIC) return -EINVAL; /* auto should be dynamic if in PS mode */ - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) && + if (!(local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) && (smps_mode == IEEE80211_SMPS_DYNAMIC || smps_mode == IEEE80211_SMPS_AUTOMATIC)) return -EINVAL; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index efa41fc..9d4ccb2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3805,7 +3805,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len; ifmgd->p2p_noa_index = -1; - if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) + if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; else ifmgd->req_smps = IEEE80211_SMPS_OFF; -- cgit v0.10.2 From 595a23fe1527261316e28d18cd06ac4b391d7ad1 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 5 Sep 2014 20:41:48 -0700 Subject: iwl4965: fix %d confusingly prefixed with 0x in format string Signed-off-by: Hans Wennborg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 3dcbe2c..cf7996f 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -4633,7 +4633,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr, else { ret = il_set_tx_power(il, val, false); if (ret) - IL_ERR("failed setting tx power (0x%d).\n", ret); + IL_ERR("failed setting tx power (0x%08x).\n", ret); else ret = count; } -- cgit v0.10.2 From 4f4378dead3792d21577739f07869fbd843dab23 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 5 Sep 2014 20:19:50 -0700 Subject: rtlwifi: fix %d confusingly prefixed with 0x in format strings Signed-off-by: Hans Wennborg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 67d1ee6..74a8ba4 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -646,7 +646,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) == 2) { RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, - "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%d\n", + "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n", prio, ring->idx, skb_queue_len(&ring->queue)); @@ -1469,7 +1469,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, if ((own == 1) && (hw_queue != BEACON_QUEUE)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", + "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n", hw_queue, ring->idx, idx, skb_queue_len(&ring->queue)); @@ -1511,7 +1511,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, - "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n", + "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n", hw_queue, ring->idx, idx, skb_queue_len(&ring->queue)); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 592125a..1961b8e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -677,7 +677,7 @@ static void _rtl92d_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n", + "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n", rtlphy->pwrgroup_cnt, index, rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]); if (index == 13) @@ -2531,7 +2531,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw, if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */ u4tmp = curveindex_5g[channel-1]; RTPRINT(rtlpriv, FINIT, INIT_IQK, - "ver 1 set RF-A, 5G, 0x28 = 0x%ulx !!\n", u4tmp); + "ver 1 set RF-A, 5G, 0x28 = 0x%x !!\n", u4tmp); if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && rtlpriv->rtlhal.interfaceindex == 1) { bneed_powerdown_radio = @@ -2550,7 +2550,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw, } else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) { u4tmp = curveindex_2g[channel-1]; RTPRINT(rtlpriv, FINIT, INIT_IQK, - "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp); + "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", u4tmp); if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY && rtlpriv->rtlhal.interfaceindex == 0) { bneed_powerdown_radio = @@ -2562,7 +2562,7 @@ static void _rtl92d_phy_reload_lck_setting(struct ieee80211_hw *hw, } rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp); RTPRINT(rtlpriv, FINIT, INIT_IQK, - "ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", + "ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", rtl_get_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800)); if (bneed_powerdown_radio) _rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue); -- cgit v0.10.2 From 85e6c26fb632dbf3722fa9d2d788cd4f7993c943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 9 Sep 2014 21:17:06 +0200 Subject: b43: HT-PHY: Move radio preparation into init function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Radio should be prepared only before initialization. We need this to be able to call b43_radio_2059_init conditionally (in the future). This also documents RF control register a bit. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index c4dc8b0..7b44541 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -89,6 +89,14 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, udelay(300); } +static void b43_radio_2059_init_pre(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU); + b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_FORCE); + b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_FORCE); + b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_CHIP0_PU); +} + static void b43_radio_2059_init(struct b43_wldev *dev) { const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 }; @@ -97,6 +105,9 @@ static void b43_radio_2059_init(struct b43_wldev *dev) }; u16 i, j; + /* Prepare (reset?) radio */ + b43_radio_2059_init_pre(dev); + b43_radio_write(dev, R2059_ALL | 0x51, 0x0070); b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003); @@ -1002,19 +1013,10 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev, if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED) b43err(dev->wl, "MAC not suspended\n"); - /* In the following PHY ops we copy wl's dummy behaviour. - * TODO: Find out if reads (currently hidden in masks/masksets) are - * needed and replace following ops with just writes or w&r. - * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can - * cause delayed (!) machine lock up. */ if (blocked) { - b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0); + b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, + ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU); } else { - b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0); - b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1); - b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0); - b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2); - if (dev->phy.radio_ver == 0x2059) b43_radio_2059_init(dev); else diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h index 6cae370..67b208e 100644 --- a/drivers/net/wireless/b43/phy_ht.h +++ b/drivers/net/wireless/b43/phy_ht.h @@ -81,7 +81,9 @@ #define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004) /* Values for the status are the same as for the trigger */ -#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010) +#define B43_PHY_HT_RF_CTL_CMD 0x810 +#define B43_PHY_HT_RF_CTL_CMD_FORCE 0x0001 +#define B43_PHY_HT_RF_CTL_CMD_CHIP0_PU 0x0002 #define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c) #define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c) -- cgit v0.10.2 From 5db4a37bec723d0095f9a0f0ef47b56482bf36c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 9 Sep 2014 21:17:07 +0200 Subject: b43: HT-PHY: Move radio calibration to separated functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also use b43_radio_wait_value to simplify the code and usleep_range when needed. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 7b44541..ff31c20 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -89,6 +89,50 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, udelay(300); } +/* Calibrate resistors in LPF of PLL? */ +static void b43_radio_2059_rcal(struct b43_wldev *dev) +{ + b43_radio_set(dev, R2059_C3 | 0x4, 0x1); + usleep_range(10, 20); + b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1); + b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2); + + b43_radio_set(dev, R2059_C3 | 0x4, 0x2); + usleep_range(100, 200); + b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2); + + if (!b43_radio_wait_value(dev, R2059_C3 | 0x145, 1, 1, 100, + 1000000)) + b43err(dev->wl, "Radio 0x2059 rcal timeout\n"); + + b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1); + b43_radio_set(dev, 0xa, 0x60); +} + +/* Calibrate the internal RC oscillator? */ +static void b43_radio_2057_rccal(struct b43_wldev *dev) +{ + const u16 radio_values[3][2] = { + { 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 }, + }; + int i; + + for (i = 0; i < 3; i++) { + b43_radio_write(dev, 0x17F, radio_values[i][0]); + b43_radio_write(dev, 0x13D, 0x6E); + b43_radio_write(dev, 0x13E, radio_values[i][1]); + b43_radio_write(dev, 0x13C, 0x55); + + if (!b43_radio_wait_value(dev, 0x140, 2, 2, + 500, 5000000)) + b43err(dev->wl, "Radio 0x2059 rccal timeout\n"); + + b43_radio_write(dev, 0x13C, 0x15); + } + + b43_radio_mask(dev, 0x17F, ~0x1); +} + static void b43_radio_2059_init_pre(struct b43_wldev *dev) { b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU); @@ -100,10 +144,7 @@ static void b43_radio_2059_init_pre(struct b43_wldev *dev) static void b43_radio_2059_init(struct b43_wldev *dev) { const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 }; - const u16 radio_values[3][2] = { - { 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 }, - }; - u16 i, j; + int i; /* Prepare (reset?) radio */ b43_radio_2059_init_pre(dev); @@ -121,48 +162,8 @@ static void b43_radio_2059_init(struct b43_wldev *dev) b43_radio_mask(dev, 0xc0, ~0x0080); if (1) { /* FIXME */ - b43_radio_set(dev, R2059_C3 | 0x4, 0x1); - udelay(10); - b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1); - b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2); - - b43_radio_set(dev, R2059_C3 | 0x4, 0x2); - udelay(100); - b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2); - - for (i = 0; i < 10000; i++) { - if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) { - i = 0; - break; - } - udelay(100); - } - if (i) - b43err(dev->wl, "radio 0x945 timeout\n"); - - b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1); - b43_radio_set(dev, 0xa, 0x60); - - for (i = 0; i < 3; i++) { - b43_radio_write(dev, 0x17F, radio_values[i][0]); - b43_radio_write(dev, 0x13D, 0x6E); - b43_radio_write(dev, 0x13E, radio_values[i][1]); - b43_radio_write(dev, 0x13C, 0x55); - - for (j = 0; j < 10000; j++) { - if (b43_radio_read(dev, 0x140) & 2) { - j = 0; - break; - } - udelay(500); - } - if (j) - b43err(dev->wl, "radio 0x140 timeout\n"); - - b43_radio_write(dev, 0x13C, 0x15); - } - - b43_radio_mask(dev, 0x17F, ~0x1); + b43_radio_2059_rcal(dev); + b43_radio_2057_rccal(dev); } b43_radio_mask(dev, 0x11, ~0x0008); -- cgit v0.10.2 From 28f051f5540091417c5bc05ac2016480d697fd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 9 Sep 2014 21:17:08 +0200 Subject: b43: HT-PHY: Define some regs for 0x2059 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index ff31c20..d346053 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -81,10 +81,10 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, udelay(50); /* Calibration */ - b43_radio_mask(dev, 0x2b, ~0x1); - b43_radio_mask(dev, 0x2e, ~0x4); - b43_radio_set(dev, 0x2e, 0x4); - b43_radio_set(dev, 0x2b, 0x1); + b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1); + b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4); + b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4); + b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1); udelay(300); } @@ -92,20 +92,27 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev, /* Calibrate resistors in LPF of PLL? */ static void b43_radio_2059_rcal(struct b43_wldev *dev) { - b43_radio_set(dev, R2059_C3 | 0x4, 0x1); + /* Enable */ + b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1); usleep_range(10, 20); + b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1); b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2); - b43_radio_set(dev, R2059_C3 | 0x4, 0x2); + /* Start */ + b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2); usleep_range(100, 200); - b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2); - if (!b43_radio_wait_value(dev, R2059_C3 | 0x145, 1, 1, 100, + /* Stop */ + b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2); + + if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100, 1000000)) b43err(dev->wl, "Radio 0x2059 rcal timeout\n"); - b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1); + /* Disable */ + b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1); + b43_radio_set(dev, 0xa, 0x60); } @@ -118,19 +125,23 @@ static void b43_radio_2057_rccal(struct b43_wldev *dev) int i; for (i = 0; i < 3; i++) { - b43_radio_write(dev, 0x17F, radio_values[i][0]); - b43_radio_write(dev, 0x13D, 0x6E); - b43_radio_write(dev, 0x13E, radio_values[i][1]); - b43_radio_write(dev, 0x13C, 0x55); + b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]); + b43_radio_write(dev, R2059_RCCAL_X1, 0x6E); + b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]); - if (!b43_radio_wait_value(dev, 0x140, 2, 2, + /* Start */ + b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55); + + /* Wait */ + if (!b43_radio_wait_value(dev, R2059_RCCAL_DONE_OSCCAP, 2, 2, 500, 5000000)) b43err(dev->wl, "Radio 0x2059 rccal timeout\n"); - b43_radio_write(dev, 0x13C, 0x15); + /* Stop */ + b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x15); } - b43_radio_mask(dev, 0x17F, ~0x1); + b43_radio_mask(dev, R2059_RCCAL_MASTER, ~0x1); } static void b43_radio_2059_init_pre(struct b43_wldev *dev) @@ -155,18 +166,20 @@ static void b43_radio_2059_init(struct b43_wldev *dev) for (i = 0; i < ARRAY_SIZE(routing); i++) b43_radio_set(dev, routing[i] | 0x146, 0x3); - b43_radio_set(dev, 0x2e, 0x0078); - b43_radio_set(dev, 0xc0, 0x0080); + /* Post init starts below */ + + b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x0078); + b43_radio_set(dev, R2059_XTAL_CONFIG2, 0x0080); msleep(2); - b43_radio_mask(dev, 0x2e, ~0x0078); - b43_radio_mask(dev, 0xc0, ~0x0080); + b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x0078); + b43_radio_mask(dev, R2059_XTAL_CONFIG2, ~0x0080); if (1) { /* FIXME */ b43_radio_2059_rcal(dev); b43_radio_2057_rccal(dev); } - b43_radio_mask(dev, 0x11, ~0x0008); + b43_radio_mask(dev, R2059_RFPLL_MASTER, ~0x0008); } /************************************************** diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h index 40a82d7..9d828d5 100644 --- a/drivers/net/wireless/b43/radio_2059.h +++ b/drivers/net/wireless/b43/radio_2059.h @@ -10,6 +10,18 @@ #define R2059_C3 0x800 #define R2059_ALL 0xC00 +#define R2059_RCAL_CONFIG 0x004 +#define R2059_RFPLL_MASTER 0x011 +#define R2059_RFPLL_MISC_EN 0x02b +#define R2059_RFPLL_MISC_CAL_RESETN 0x02e +#define R2059_XTAL_CONFIG2 0x0c0 +#define R2059_RCCAL_START_R1_Q1_P1 0x13c +#define R2059_RCCAL_X1 0x13d +#define R2059_RCCAL_TRC0 0x13e +#define R2059_RCCAL_DONE_OSCCAP 0x140 +#define R2059_RCAL_STATUS 0x145 +#define R2059_RCCAL_MASTER 0x17f + /* Values for various registers uploaded on channel switching */ struct b43_phy_ht_channeltab_e_radio2059 { /* The channel frequency in MHz */ -- cgit v0.10.2 From ea422b2c33c7bf253c5e64c82cfb68363cf40d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 9 Sep 2014 21:17:09 +0200 Subject: b43: HT-PHY: Complete radio init (add missing entries) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index d346053..de52d48 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -160,8 +160,7 @@ static void b43_radio_2059_init(struct b43_wldev *dev) /* Prepare (reset?) radio */ b43_radio_2059_init_pre(dev); - b43_radio_write(dev, R2059_ALL | 0x51, 0x0070); - b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003); + r2059_upload_inittabs(dev); for (i = 0; i < ARRAY_SIZE(routing); i++) b43_radio_set(dev, routing[i] | 0x146, 0x3); diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c index 38e31d8..b2a53b2 100644 --- a/drivers/net/wireless/b43/radio_2059.c +++ b/drivers/net/wireless/b43/radio_2059.c @@ -25,6 +25,13 @@ #include "b43.h" #include "radio_2059.h" +/* Extracted from MMIO dump of 6.30.223.141 */ +static u16 r2059_phy_rev1_init[][2] = { + { 0x051, 0x70 }, { 0x05a, 0x03 }, { 0x079, 0x01 }, { 0x082, 0x70 }, + { 0x083, 0x00 }, { 0x084, 0x70 }, { 0x09a, 0x7f }, { 0x0b6, 0x10 }, + { 0x188, 0x05 }, +}; + #define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ r20) \ @@ -139,6 +146,26 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi }, }; +void r2059_upload_inittabs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 *table = NULL; + u16 size, i; + + switch (phy->rev) { + case 1: + table = r2059_phy_rev1_init[0]; + size = ARRAY_SIZE(r2059_phy_rev1_init); + break; + default: + B43_WARN_ON(1); + return; + } + + for (i = 0; i < size; i++, table += 2) + b43_radio_write(dev, R2059_ALL | table[0], table[1]); +} + const struct b43_phy_ht_channeltab_e_radio2059 *b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq) { diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h index 9d828d5..9e22fb6 100644 --- a/drivers/net/wireless/b43/radio_2059.h +++ b/drivers/net/wireless/b43/radio_2059.h @@ -52,6 +52,8 @@ struct b43_phy_ht_channeltab_e_radio2059 { struct b43_phy_ht_channeltab_e_phy phy_regs; }; +void r2059_upload_inittabs(struct b43_wldev *dev); + const struct b43_phy_ht_channeltab_e_radio2059 *b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq); -- cgit v0.10.2 From dbb30ebeefaf01121b32ae6b5baf29524f3a0b30 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 9 Sep 2014 15:57:46 -0500 Subject: rtlwifi: btcoexist: Fix "always true" warning from commit ed364abffd6e The 0-DAY kernel build testing backend reports the following warning: drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c:516 halbtc_bitmask_write_1byte() warn: always true condition '(bit_mask != 4294967295) => (0-255 != u32max)' This problem was introduced in commit ed364abffd6e19bec67b7ccda8237213b8b37640, and arises because the caller of halbtc_bitmask_write_1byte() is using a u8 rather than a u32 for the data. Reported-by: Kbuild test robot Signed-off-by: Larry Finger Cc: Kbuild test robot Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index 3119e8b..0620b22 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -497,7 +497,7 @@ static u32 halbtc_read_4byte(void *bt_context, u32 reg_addr) return rtl_read_dword(rtlpriv, reg_addr); } -static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data) +static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u32 data) { struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context; struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index eae1937..0d185e6 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -359,7 +359,7 @@ typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr); typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr); -typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data); +typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u32 data); typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr, u8 bit_mask, u8 data1b); -- cgit v0.10.2 From bc944506551536dca2b85188b34cc2cf556492db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 10 Sep 2014 09:07:13 +0200 Subject: b43: HT-PHY: Set MAC frequency to correct values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I misunderstood original Broadcom comment and used wrong values. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 66ff718..165dbc3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2985,7 +2985,22 @@ void b43_mac_switch_freq(struct b43_wldev *dev, u8 spurmode) { u16 chip_id = dev->dev->chip_id; - if (chip_id == BCMA_CHIP_ID_BCM43131 || + if (chip_id == BCMA_CHIP_ID_BCM4331) { + switch (spurmode) { + case 2: /* 168 Mhz: 2^26/168 = 0x61862 */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6); + break; + case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6); + break; + default: /* 160 Mhz: 2^26/160 = 0x66666 */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6); + break; + } + } else if (chip_id == BCMA_CHIP_ID_BCM43131 || chip_id == BCMA_CHIP_ID_BCM43217 || chip_id == BCMA_CHIP_ID_BCM43222 || chip_id == BCMA_CHIP_ID_BCM43224 || diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index de52d48..a379602 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -728,7 +728,6 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev, { struct bcma_device *core = dev->dev->bdev; int spuravoid = 0; - u16 tmp; /* Check for 13 and 14 is just a guess, we don't have enough logs. */ if (new_channel->hw_value == 13 || new_channel->hw_value == 14) @@ -741,20 +740,7 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev, B43_BCMA_CLKCTLST_80211_PLL_ST | B43_BCMA_CLKCTLST_PHY_PLL_ST, false); - /* Values has been taken from wlc_bmac_switch_macfreq comments */ - switch (spuravoid) { - case 2: /* 126MHz */ - tmp = 0x2082; - break; - case 1: /* 123MHz */ - tmp = 0x5341; - break; - default: /* 120MHz */ - tmp = 0x8889; - } - - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp); - b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + b43_mac_switch_freq(dev, spuravoid); /* TODO: reset PLL */ -- cgit v0.10.2 From 151a9706503fe9274254d09742e550466c0b7537 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:30 +0300 Subject: wil6210: firmware download Firmware download implemented but is still experimental feature; flag controlling it added, no_fw_load. It is true by default, use no_fw_load=N to activate feature. Reset flows also got some adjustment for the fw download to work Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index c7a3465..dc788a1 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -10,6 +10,7 @@ wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o +wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c new file mode 100644 index 0000000..8c6f3b0 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include "wil6210.h" +#include "fw.h" + +MODULE_FIRMWARE(WIL_FW_NAME); + +/* target operations */ +/* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a)) +/* register write. wmb() to make sure it is completed */ +#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) +/* register set = read, OR, write */ +#define S(a, v) W(a, R(a) | v) +/* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) + +static +void wil_memset_toio_32(volatile void __iomem *dst, u32 val, + size_t count) +{ + volatile u32 __iomem *d = dst; + + for (count += 4; count > 4; count -= 4) + __raw_writel(val, d++); +} + +#include "fw_inc.c" diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h new file mode 100644 index 0000000..7a2c6c1 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */ +#define WIL_FW_FMT_VERSION (1) /* format version driver supports */ + +enum wil_fw_record_type { + wil_fw_type_comment = 1, + wil_fw_type_data = 2, + wil_fw_type_fill = 3, + wil_fw_type_action = 4, + wil_fw_type_verify = 5, + wil_fw_type_file_header = 6, + wil_fw_type_direct_write = 7, + wil_fw_type_gateway_data = 8, + wil_fw_type_gateway_data4 = 9, +}; + +struct wil_fw_record_head { + __le16 type; /* enum wil_fw_record_type */ + __le16 flags; /* to be defined */ + __le32 size; /* whole record, bytes after head */ +} __packed; + +/* data block. write starting from @addr + * data_size inferred from the @head.size. For this case, + * data_size = @head.size - offsetof(struct wil_fw_record_data, data) + */ +struct wil_fw_record_data { /* type == wil_fw_type_data */ + __le32 addr; + __le32 data[0]; /* [data_size], see above */ +} __packed; + +/* fill with constant @value, @size bytes starting from @addr */ +struct wil_fw_record_fill { /* type == wil_fw_type_fill */ + __le32 addr; + __le32 value; + __le32 size; +} __packed; + +/* free-form comment + * for informational purpose, data_size is @head.size from record header + */ +struct wil_fw_record_comment { /* type == wil_fw_type_comment */ + u8 data[0]; /* free-form data [data_size], see above */ +} __packed; + +/* perform action + * data_size = @head.size - offsetof(struct wil_fw_record_action, data) + */ +struct wil_fw_record_action { /* type == wil_fw_type_action */ + __le32 action; /* action to perform: reset, wait for fw ready etc. */ + __le32 data[0]; /* action specific, [data_size], see above */ +} __packed; + +/* data block for struct wil_fw_record_direct_write */ +struct wil_fw_data_dwrite { + __le32 addr; + __le32 value; + __le32 mask; +} __packed; + +/* write @value to the @addr, + * preserve original bits accordingly to the @mask + * data_size is @head.size where @head is record header + */ +struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */ + struct wil_fw_data_dwrite data[0]; +} __packed; + +/* verify condition: [@addr] & @mask == @value + * if condition not met, firmware download fails + */ +struct wil_fw_record_verify { /* type == wil_fw_verify */ + __le32 addr; /* read from this address */ + __le32 value; /* reference value */ + __le32 mask; /* mask for verification */ +} __packed; + +/* file header + * First record of every file + */ +struct wil_fw_record_file_header { + __le32 signature ; /* Wilocity signature */ + __le32 reserved; + __le32 crc; /* crc32 of the following data */ + __le32 version; /* format version */ + __le32 data_len; /* total data in file, including this record */ + u8 comment[32]; /* short description */ +} __packed; + +/* 1-dword gateway */ +/* data block for the struct wil_fw_record_gateway_data */ +struct wil_fw_data_gw { + __le32 addr; + __le32 value; +} __packed; + +/* gateway write block. + * write starting address and values from the data buffer + * through the gateway + * data_size inferred from the @head.size. For this case, + * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data, data) + */ +struct wil_fw_record_gateway_data { /* type == wil_fw_type_gateway_data */ + __le32 gateway_addr_addr; + __le32 gateway_value_addr; + __le32 gateway_cmd_addr; + __le32 gateway_ctrl_address; +#define WIL_FW_GW_CTL_BUSY BIT(29) /* gateway busy performing operation */ +#define WIL_FW_GW_CTL_RUN BIT(30) /* start gateway operation */ + __le32 command; + struct wil_fw_data_gw data[0]; /* total size [data_size], see above */ +} __packed; + +/* 4-dword gateway */ +/* data block for the struct wil_fw_record_gateway_data4 */ +struct wil_fw_data_gw4 { + __le32 addr; + __le32 value[4]; +} __packed; + +/* gateway write block. + * write starting address and values from the data buffer + * through the gateway + * data_size inferred from the @head.size. For this case, + * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data4, data) + */ +struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */ + __le32 gateway_addr_addr; + __le32 gateway_value_addr[4]; + __le32 gateway_cmd_addr; + __le32 gateway_ctrl_address; /* same logic as for 1-dword gw */ + __le32 command; + struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */ +} __packed; diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c new file mode 100644 index 0000000..44cb71f --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Algorithmic part of the firmware download. + * To be included in the container file providing framework + */ + +#define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg) +#define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg) +#define wil_hex_dump_fw(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) \ + print_hex_dump_debug("DBG[ FW ]" prefix_str, \ + prefix_type, rowsize, \ + groupsize, buf, len, ascii) + +#define FW_ADDR_CHECK(ioaddr, val, msg) do { \ + ioaddr = wmi_buffer(wil, val); \ + if (!ioaddr) { \ + wil_err_fw(wil, "bad " msg ": 0x%08x\n", \ + le32_to_cpu(val)); \ + return -EINVAL; \ + } \ + } while (0) + +/** + * wil_fw_verify - verify firmware file validity + * + * perform various checks for the firmware file header. + * records are not validated. + * + * Return file size or negative error + */ +static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size) +{ + const struct wil_fw_record_head *hdr = (const void *)data; + struct wil_fw_record_file_header fh; + const struct wil_fw_record_file_header *fh_; + u32 crc; + u32 dlen; + + if (size % 4) { + wil_err_fw(wil, "image size not aligned: %zu\n", size); + return -EINVAL; + } + /* have enough data for the file header? */ + if (size < sizeof(*hdr) + sizeof(fh)) { + wil_err_fw(wil, "file too short: %zu bytes\n", size); + return -EINVAL; + } + + /* start with the file header? */ + if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) { + wil_err_fw(wil, "no file header\n"); + return -EINVAL; + } + + /* data_len */ + fh_ = (struct wil_fw_record_file_header *)&hdr[1]; + dlen = le32_to_cpu(fh_->data_len); + if (dlen % 4) { + wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen); + return -EINVAL; + } + if (size < dlen) { + wil_err_fw(wil, "file truncated at %zu/%lu\n", + size, (ulong)dlen); + return -EINVAL; + } + if (dlen < sizeof(*hdr) + sizeof(fh)) { + wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen); + return -EINVAL; + } + + /* signature */ + if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) { + wil_err_fw(wil, "bad header signature: 0x%08x\n", + le32_to_cpu(fh_->signature)); + return -EINVAL; + } + + /* version */ + if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) { + wil_err_fw(wil, "unsupported header version: %d\n", + le32_to_cpu(fh_->version)); + return -EINVAL; + } + + /* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/ + fh = *fh_; + fh.crc = 0; + + crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr)); + crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh)); + crc = crc32_le(crc, (unsigned char const *)&fh_[1], + dlen - sizeof(*hdr) - sizeof(fh)); + crc = ~crc; + + if (crc != le32_to_cpu(fh_->crc)) { + wil_err_fw(wil, "checksum mismatch:" + " calculated for %lu bytes 0x%08x != 0x%08x\n", + (ulong)dlen, crc, le32_to_cpu(fh_->crc)); + return -EINVAL; + } + + return (int)dlen; +} + +static int fw_handle_comment(struct wil6210_priv *wil, const void *data, + size_t size) +{ + wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true); + + return 0; +} + +static int fw_handle_data(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_data *d = data; + void __iomem *dst; + size_t s = size - sizeof(*d); + + if (size < sizeof(*d) + sizeof(u32)) { + wil_err_fw(wil, "data record too short: %zu\n", size); + return -EINVAL; + } + + FW_ADDR_CHECK(dst, d->addr, "address"); + wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr), + s); + wil_memcpy_toio_32(dst, d->data, s); + wmb(); /* finish before processing next record */ + + return 0; +} + +static int fw_handle_fill(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_fill *d = data; + void __iomem *dst; + u32 v; + size_t s = (size_t)le32_to_cpu(d->size); + + if (size != sizeof(*d)) { + wil_err_fw(wil, "bad size for fill record: %zu\n", size); + return -EINVAL; + } + + if (s < sizeof(u32)) { + wil_err_fw(wil, "fill size too short: %zu\n", s); + return -EINVAL; + } + + if (s % sizeof(u32)) { + wil_err_fw(wil, "fill size not aligned: %zu\n", s); + return -EINVAL; + } + + FW_ADDR_CHECK(dst, d->addr, "address"); + + v = le32_to_cpu(d->value); + wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n", + le32_to_cpu(d->addr), v, s); + wil_memset_toio_32(dst, v, s); + wmb(); /* finish before processing next record */ + + return 0; +} + +static int fw_handle_file_header(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_file_header *d = data; + + if (size != sizeof(*d)) { + wil_err_fw(wil, "file header length incorrect: %zu\n", size); + return -EINVAL; + } + + wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n", + d->version, d->data_len); + wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment, + sizeof(d->comment), true); + + return 0; +} + +static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_direct_write *d = data; + const struct wil_fw_data_dwrite *block = d->data; + int n, i; + + if (size % sizeof(*block)) { + wil_err_fw(wil, "record size not aligned on %zu: %zu\n", + sizeof(*block), size); + return -EINVAL; + } + n = size / sizeof(*block); + + for (i = 0; i < n; i++) { + void __iomem *dst; + u32 m = le32_to_cpu(block[i].mask); + u32 v = le32_to_cpu(block[i].value); + u32 x, y; + + FW_ADDR_CHECK(dst, block[i].addr, "address"); + + x = ioread32(dst); + y = (x & m) | (v & ~m); + wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x " + "(old 0x%08x val 0x%08x mask 0x%08x)\n", + le32_to_cpu(block[i].addr), y, x, v, m); + iowrite32(y, dst); + wmb(); /* finish before processing next record */ + } + + return 0; +} + +static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr, + void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd, + u32 a) +{ + unsigned delay = 0; + + iowrite32(a, gwa_addr); + iowrite32(gw_cmd, gwa_cmd); + wmb(); /* finish before activate gw */ + + iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ + do { + udelay(1); /* typical time is few usec */ + if (delay++ > 100) { + wil_err_fw(wil, "gw timeout\n"); + return -EINVAL; + } + } while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ + + return 0; +} + +static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_gateway_data *d = data; + const struct wil_fw_data_gw *block = d->data; + void __iomem *gwa_addr; + void __iomem *gwa_val; + void __iomem *gwa_cmd; + void __iomem *gwa_ctl; + u32 gw_cmd; + int n, i; + + if (size < sizeof(*d) + sizeof(*block)) { + wil_err_fw(wil, "gateway record too short: %zu\n", size); + return -EINVAL; + } + + if ((size - sizeof(*d)) % sizeof(*block)) { + wil_err_fw(wil, "gateway record data size" + " not aligned on %zu: %zu\n", + sizeof(*block), size - sizeof(*d)); + return -EINVAL; + } + n = (size - sizeof(*d)) / sizeof(*block); + + gw_cmd = le32_to_cpu(d->command); + + wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n", + n, gw_cmd); + + FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); + FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr"); + FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); + FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + + wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x" + " cmd 0x%08x ctl 0x%08x\n", + le32_to_cpu(d->gateway_addr_addr), + le32_to_cpu(d->gateway_value_addr), + le32_to_cpu(d->gateway_cmd_addr), + le32_to_cpu(d->gateway_ctrl_address)); + + for (i = 0; i < n; i++) { + int rc; + u32 a = le32_to_cpu(block[i].addr); + u32 v = le32_to_cpu(block[i].value); + + wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n", + i, a, v); + + iowrite32(v, gwa_val); + rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); + if (rc) + return rc; + } + + return 0; +} + +static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_gateway_data4 *d = data; + const struct wil_fw_data_gw4 *block = d->data; + void __iomem *gwa_addr; + void __iomem *gwa_val[ARRAY_SIZE(block->value)]; + void __iomem *gwa_cmd; + void __iomem *gwa_ctl; + u32 gw_cmd; + int n, i, k; + + if (size < sizeof(*d) + sizeof(*block)) { + wil_err_fw(wil, "gateway4 record too short: %zu\n", size); + return -EINVAL; + } + + if ((size - sizeof(*d)) % sizeof(*block)) { + wil_err_fw(wil, "gateway4 record data size" + " not aligned on %zu: %zu\n", + sizeof(*block), size - sizeof(*d)); + return -EINVAL; + } + n = (size - sizeof(*d)) / sizeof(*block); + + gw_cmd = le32_to_cpu(d->command); + + wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n", + n, gw_cmd); + + FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr"); + for (k = 0; k < ARRAY_SIZE(block->value); k++) + FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k], + "gateway_value_addr"); + FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr"); + FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address"); + + wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n", + le32_to_cpu(d->gateway_addr_addr), + le32_to_cpu(d->gateway_cmd_addr), + le32_to_cpu(d->gateway_ctrl_address)); + wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4, + d->gateway_value_addr, sizeof(d->gateway_value_addr), + false); + + for (i = 0; i < n; i++) { + int rc; + u32 a = le32_to_cpu(block[i].addr); + u32 v[ARRAY_SIZE(block->value)]; + + for (k = 0; k < ARRAY_SIZE(block->value); k++) + v[k] = le32_to_cpu(block[i].value[k]); + + wil_dbg_fw(wil, " gw4 write[%3d] [0x%08x] <==\n", i, a); + wil_hex_dump_fw(" val ", DUMP_PREFIX_NONE, 16, 4, v, + sizeof(v), false); + + for (k = 0; k < ARRAY_SIZE(block->value); k++) + iowrite32(v[k], gwa_val[k]); + rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); + if (rc) + return rc; + } + + return 0; +} + +static const struct { + int type; + int (*handler)(struct wil6210_priv *wil, const void *data, size_t size); +} wil_fw_handlers[] = { + {wil_fw_type_comment, fw_handle_comment}, + {wil_fw_type_data, fw_handle_data}, + {wil_fw_type_fill, fw_handle_fill}, + /* wil_fw_type_action */ + /* wil_fw_type_verify */ + {wil_fw_type_file_header, fw_handle_file_header}, + {wil_fw_type_direct_write, fw_handle_direct_write}, + {wil_fw_type_gateway_data, fw_handle_gateway_data}, + {wil_fw_type_gateway_data4, fw_handle_gateway_data4}, +}; + +static int wil_fw_handle_record(struct wil6210_priv *wil, int type, + const void *data, size_t size) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) { + if (wil_fw_handlers[i].type == type) + return wil_fw_handlers[i].handler(wil, data, size); + } + + wil_err_fw(wil, "unknown record type: %d\n", type); + return -EINVAL; +} + +/** + * wil_fw_load - load FW into device + * + * Load the FW and uCode code and data to the corresponding device + * memory regions + * + * Return error code + */ +static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) +{ + int rc = 0; + const struct wil_fw_record_head *hdr; + size_t s, hdr_sz; + + for (hdr = data;; hdr = (const void *)hdr + s, size -= s) { + if (size < sizeof(*hdr)) + break; + hdr_sz = le32_to_cpu(hdr->size); + s = sizeof(*hdr) + hdr_sz; + if (s > size) + break; + if (hdr_sz % 4) { + wil_err_fw(wil, "unaligned record size: %zu\n", + hdr_sz); + return -EINVAL; + } + rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type), + &hdr[1], hdr_sz); + if (rc) + return rc; + } + if (size) { + wil_err_fw(wil, "unprocessed bytes: %zu\n", size); + if (size >= sizeof(*hdr)) { + wil_err_fw(wil, "Stop at offset %ld" + " record type %d [%zd bytes]\n", + (const void *)hdr - data, + le16_to_cpu(hdr->type), hdr_sz); + } + return -EINVAL; + } + /* Mark FW as loaded from host */ + S(RGF_USER_USAGE_6, 1); + + return rc; +} + +/** + * wil_request_firmware - Request firmware and load to device + * + * Request firmware image from the file and load it to device + * + * Return error code + */ +int wil_request_firmware(struct wil6210_priv *wil, const char *name) +{ + int rc, rc1; + const struct firmware *fw; + size_t sz; + const void *d; + + rc = request_firmware(&fw, name, wil_to_pcie_dev(wil)); + if (rc) { + wil_err_fw(wil, "Failed to load firmware %s\n", name); + return rc; + } + wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); + + for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) { + rc1 = wil_fw_verify(wil, d, sz); + if (rc1 < 0) { + rc = rc1; + goto out; + } + rc = wil_fw_load(wil, d, rc1); + if (rc < 0) + goto out; + } + +out: + release_firmware(fw); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 98bfbb6..6411651 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -522,6 +522,7 @@ void wil6210_clear_irq(struct wil6210_priv *wil) offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); + wmb(); /* make sure write completed */ } int wil6210_init_irq(struct wil6210_priv *wil, int irq) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index b69d90f..7dfbcfb 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -25,6 +25,10 @@ static bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery"); +static bool no_fw_load = true; +module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); + #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ @@ -312,6 +316,28 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } +/* target operations */ +/* register read */ +#define R(a) ioread32(wil->csr + HOSTADDR(a)) +/* register write. wmb() to make sure it is completed */ +#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) +/* register set = read, OR, write */ +#define S(a, v) W(a, R(a) | v) +/* register clear = read, AND with inverted, write */ +#define C(a, v) W(a, R(a) & ~v) + +static inline void wil_halt_cpu(struct wil6210_priv *wil) +{ + W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); + W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST); +} + +static inline void wil_release_cpu(struct wil6210_priv *wil) +{ + /* Start CPU */ + W(RGF_USER_USER_CPU_0, 1); +} + static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; @@ -321,60 +347,41 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name); - /* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) - /* register write */ -#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) - /* register set = read, OR, write */ -#define S(a, v) W(a, R(a) | v) - /* register clear = read, AND with inverted, write */ -#define C(a, v) W(a, R(a) & ~v) - - wmb(); /* If host reorder writes here -> race in NIC */ - W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ wil->hw_version = R(RGF_USER_FW_REV_ID); rev_id = wil->hw_version & 0xff; /* Clear MAC link up */ S(RGF_HP_CTRL, BIT(15)); - /* hpal_perst_from_pad_src_n_mask */ - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); - /* car_perst_rst_src_n_mask */ - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); - wmb(); /* order is important here */ + S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); + S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); + + wil_halt_cpu(wil); + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */ if (is_sparrow) { W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - wmb(); /* order is important here */ + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); } - W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ - wmb(); /* If host reorder writes here -> race in NIC */ - W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ - wmb(); /* order is important here */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); - wmb(); /* order is important here */ + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); if (is_sparrow) { W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - wmb(); /* order is important here */ + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); } W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - wmb(); /* order is important here */ if (is_sparrow) { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); /* reset A2 PCIE AHB */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } else { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); if (rev_id == 1) { @@ -389,7 +396,6 @@ static int wil_target_reset(struct wil6210_priv *wil) /* TODO: check order here!!! Erez code is different */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - wmb(); /* order is important here */ /* wait until device ready. typical time is 200..250 msec */ do { @@ -407,16 +413,15 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); - wmb(); /* order is important here */ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; +} #undef R #undef W #undef S #undef C -} void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) { @@ -480,12 +485,36 @@ int wil_reset(struct wil6210_priv *wil) if (rc) return rc; + if (!no_fw_load) { + wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME); + wil_halt_cpu(wil); + /* Loading f/w from the file */ + rc = wil_request_firmware(wil, WIL_FW_NAME); + if (rc) + return rc; + + /* clear any interrupts which on-card-firmware may have set */ + wil6210_clear_irq(wil); + { /* CAF_ICR - clear and mask */ + u32 a = HOSTADDR(RGF_CAF_ICR) + + offsetof(struct RGF_ICR, ICR); + u32 m = HOSTADDR(RGF_CAF_ICR) + + offsetof(struct RGF_ICR, IMV); + u32 icr = ioread32(wil->csr + a); + + iowrite32(icr, wil->csr + a); /* W1C */ + iowrite32(~0, wil->csr + m); + wmb(); /* wait for completion */ + } + wil_release_cpu(wil); + } else { + wil_info(wil, "Use firmware from on-card flash\n"); + } /* init after reset */ wil->pending_connect_cid = -1; reinit_completion(&wil->wmi_ready); - /* TODO: release MAC reset */ wil6210_enable_irq(wil); /* we just started MAC, wait for FW ready */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f8718fe..063beaf 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -23,6 +23,7 @@ #include #define WIL_NAME "wil6210" +#define WIL_FW_NAME "wil6210.fw" struct wil_board { int board; @@ -86,22 +87,29 @@ struct RGF_ICR { /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) +#define RGF_USER_USAGE_6 (0x880018) #define RGF_USER_HW_MACHINE_STATE (0x8801dc) #define HW_MACHINE_BOOT_DONE (0x3fffffd) #define RGF_USER_USER_CPU_0 (0x8801e0) + #define BIT_USER_USER_CPU_MAN_RST BIT(1) /* user_cpu_man_rst */ #define RGF_USER_MAC_CPU_0 (0x8801fc) + #define BIT_USER_MAC_CPU_MAN_RST BIT(1) /* mac_cpu_man_rst */ #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ #define RGF_USER_CLKS_CTL_0 (0x880abc) + #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */ #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) + #define BIT_HPAL_PERST_FROM_PAD BIT(6) + #define BIT_CAR_PERST_RST BIT(7) #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18) +#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -136,6 +144,8 @@ struct RGF_ICR { /* MAC timer, usec, for packet lifetime */ #define RGF_MAC_MTRL_COUNTER_0 (0x886aa8) +#define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */ + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -435,6 +445,7 @@ struct wil6210_priv { #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) +#define wil_to_pcie_dev(i) (&i->pdev->dev) int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); int wil_err(struct wil6210_priv *wil, const char *fmt, ...); @@ -547,4 +558,5 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); +int wil_request_firmware(struct wil6210_priv *wil, const char *name); #endif /* __WIL6210_H__ */ -- cgit v0.10.2 From ef77285fc3837edaaa2b2a1e431b662ed8af700a Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:31 +0300 Subject: wil6210: debug prints for vring de-allocation Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9bd920d..2cc3569 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -143,6 +143,18 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, struct device *dev = wil_to_dev(wil); size_t sz = vring->size * sizeof(vring->va[0]); + if (tx) { + int vring_index = vring - wil->vring_tx; + + wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n", + vring_index, vring->size, vring->va, + &vring->pa, vring->ctx); + } else { + wil_dbg_misc(wil, "free Rx vring [%d] 0x%p:%pad 0x%p\n", + vring->size, vring->va, + &vring->pa, vring->ctx); + } + while (!wil_vring_is_empty(vring)) { dma_addr_t pa; u16 dmalen; -- cgit v0.10.2 From 8ca26163e58bb05d5c1b74778dd21fcee6738f89 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:32 +0300 Subject: wil6210: print more information when connecting when connecting, print some info about BSS Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a00f318..df77711 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -319,6 +319,22 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, return rc; } +static void wil_print_connect_params(struct wil6210_priv *wil, + struct cfg80211_connect_params *sme) +{ + wil_info(wil, "Connecting to:\n"); + if (sme->channel) { + wil_info(wil, " Channel: %d freq %d\n", + sme->channel->hw_value, sme->channel->center_freq); + } + if (sme->bssid) + wil_info(wil, " BSSID: %pM\n", sme->bssid); + if (sme->ssid) + print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, + 16, 1, sme->ssid, sme->ssid_len, true); + wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); +} + static int wil_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) @@ -335,6 +351,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, test_bit(wil_status_fwconnected, &wil->status)) return -EALREADY; + wil_print_connect_params(wil, sme); + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); -- cgit v0.10.2 From 028e1836d3f218619a6e7f04ff1540c398deb727 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:33 +0300 Subject: wil6210: some more debug for the WMI mechanism Log worker thread start/stop; as well as every handler invocation Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b1aaaee..490c278 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1128,6 +1128,9 @@ static void wmi_event_handle(struct wil6210_priv *wil, struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]); void *evt_data = (void *)(&wmi[1]); u16 id = le16_to_cpu(wmi->id); + + wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n", + id, wil->reply_id); /* check if someone waits for this event */ if (wil->reply_id && wil->reply_id == id) { if (wil->reply_buf) { @@ -1184,9 +1187,11 @@ void wmi_event_worker(struct work_struct *work) struct pending_wmi_event *evt; struct list_head *lh; + wil_dbg_wmi(wil, "Start %s\n", __func__); while ((lh = next_wmi_ev(wil)) != NULL) { evt = list_entry(lh, struct pending_wmi_event, list); wmi_event_handle(wil, &evt->event.hdr); kfree(evt); } + wil_dbg_wmi(wil, "Finished %s\n", __func__); } -- cgit v0.10.2 From 8fe596274d08b12126b90c5b1092286f66ce6d65 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:34 +0300 Subject: wil6210: coding style fixes - parentheses, indentation, typos - seq_puts() instead of seq_printf() with single argument - sizeof(var) vs. sizeof(type) Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index df77711..cba04e5 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -296,6 +296,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, n = min(request->n_channels, 4U); for (i = 0; i < n; i++) { int ch = request->channels[i]->hw_value; + if (ch == 0) { wil_err(wil, "Scan requested for unknown frequency %dMhz\n", @@ -713,7 +714,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (rc) goto out; - netif_carrier_on(ndev); out: @@ -804,7 +804,7 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev) int rc = 0; struct wireless_dev *wdev; - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); if (!wdev) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b1c6a72..e1f9276 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -61,20 +61,22 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, if (x) seq_printf(s, "0x%08x\n", ioread32(x)); else - seq_printf(s, "???\n"); + seq_puts(s, "???\n"); if (vring->va && (vring->size < 1025)) { uint i; + for (i = 0; i < vring->size; i++) { volatile struct vring_tx_desc *d = &vring->va[i].tx; + if ((i % 64) == 0 && (i != 0)) - seq_printf(s, "\n"); + seq_puts(s, "\n"); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); } - seq_printf(s, "\n"); + seq_puts(s, "\n"); } - seq_printf(s, "}\n"); + seq_puts(s, "}\n"); } static int wil_vring_debugfs_show(struct seq_file *s, void *data) @@ -85,7 +87,7 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { - struct vring *vring = &(wil->vring_tx[i]); + struct vring *vring = &wil->vring_tx[i]; struct vring_tx_data *txdata = &wil->vring_tx_data[i]; if (vring->va) { @@ -163,7 +165,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, if (!wmi_addr(wil, r.base) || !wmi_addr(wil, r.tail) || !wmi_addr(wil, r.head)) { - seq_printf(s, " ??? pointers are garbage?\n"); + seq_puts(s, " ??? pointers are garbage?\n"); goto out; } @@ -182,6 +184,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, le32_to_cpu(d.addr)); if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { u16 len = le16_to_cpu(hdr.len); + seq_printf(s, " -> %04x %04x %04x %02x\n", le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); @@ -199,6 +202,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, wil_memcpy_fromio_32(databuf, src, len); while (n < len) { int l = min(len - n, 16); + hex_dump_to_buffer(databuf + n, l, 16, 1, printbuf, sizeof(printbuf), @@ -208,11 +212,11 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, } } } else { - seq_printf(s, "\n"); + seq_puts(s, "\n"); } } out: - seq_printf(s, "}\n"); + seq_puts(s, "}\n"); } static int wil_mbox_debugfs_show(struct seq_file *s, void *data) @@ -271,11 +275,13 @@ static int wil_debugfs_ulong_set(void *data, u64 val) *(ulong *)data = val; return 0; } + static int wil_debugfs_ulong_get(void *data, u64 *val) { *val = *(ulong *)data; return 0; } + DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, wil_debugfs_ulong_set, "%llu\n"); @@ -339,6 +345,7 @@ static const struct dbg_off isr_off[] = { {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32}, {}, }; + static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, const char *name, struct dentry *parent, u32 off) @@ -422,7 +429,7 @@ static const struct file_operations fops_memread = { }; static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { enum { max_count = 4096 }; struct debugfs_blob_wrapper *blob = file->private_data; @@ -474,6 +481,7 @@ struct dentry *wil_debugfs_create_ioblob(const char *name, { return debugfs_create_file(name, mode, parent, blob, &fops_ioblob); } + /*---reset---*/ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, size_t len, loff_t *ppos) @@ -499,6 +507,7 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; + /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, size_t len, loff_t *ppos) @@ -509,6 +518,7 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, bool on; char *kbuf = kmalloc(len + 1, GFP_KERNEL); + if (!kbuf) return -ENOMEM; if (copy_from_user(kbuf, buf, len)) { @@ -545,6 +555,7 @@ static const struct file_operations fops_rxon = { .write = wil_write_file_rxon, .open = simple_open, }; + /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, @@ -555,8 +566,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, struct wireless_dev *wdev = wil_to_wdev(wil); struct cfg80211_mgmt_tx_params params; int rc; - void *frame = kmalloc(len, GFP_KERNEL); + if (!frame) return -ENOMEM; @@ -625,8 +636,10 @@ static void wil_seq_hexdump(struct seq_file *s, void *p, int len, { char printbuf[16 * 3 + 2]; int i = 0; + while (i < len) { int l = min(len - i, 16); + hex_dump_to_buffer(p + i, l, 16, 1, printbuf, sizeof(printbuf), false); seq_printf(s, "%s%s\n", prefix, printbuf); @@ -664,10 +677,8 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) struct wil6210_priv *wil = s->private; struct vring *vring; bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); - if (tx) - vring = &(wil->vring_tx[dbg_vring_index]); - else - vring = &wil->vring_rx; + + vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx; if (!vring->va) { if (tx) @@ -682,7 +693,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) * only field used, .dma.length, is the same */ volatile struct vring_tx_desc *d = - &(vring->va[dbg_txdesc_index].tx); + &vring->va[dbg_txdesc_index].tx; volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; @@ -702,7 +713,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) wil_seq_print_skb(s, skb); kfree_skb(skb); } - seq_printf(s, "}\n"); + seq_puts(s, "}\n"); } else { if (tx) seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", @@ -816,6 +827,7 @@ static const struct file_operations fops_bf = { .read = seq_read, .llseek = seq_lseek, }; + /*---------SSID------------*/ static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -878,10 +890,10 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; u32 t_m, t_r; - int rc = wmi_get_temperature(wil, &t_m, &t_r); + if (rc) { - seq_printf(s, "Failed\n"); + seq_puts(s, "Failed\n"); return 0; } @@ -937,6 +949,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; + switch (p->status) { case wil_sta_unused: status = "unused "; @@ -997,7 +1010,6 @@ static int wil_info_debugfs_show(struct seq_file *s, void *data) rxf_old = rxf; txf_old = txf; - #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ " " __stringify(x) : "" @@ -1032,6 +1044,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + seq_printf(s, "0x%03x [", r->head_seq_num); for (i = 0; i < r->buf_size; i++) { if (i == index) @@ -1050,6 +1063,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; + switch (p->status) { case wil_sta_unused: status = "unused "; @@ -1067,6 +1081,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) if (p->status == wil_sta_connected) { for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; + if (r) { seq_printf(s, "[%2d] ", tid); wil_print_rxtid(s, r); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 7dfbcfb..4a884b4 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -71,6 +71,7 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wil_sta_info *sta = &wil->sta[cid]; + wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); @@ -227,6 +228,7 @@ static void wil_fw_error_worker(struct work_struct *work) static int wil_find_free_vring(struct wil6210_priv *wil) { int i; + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { if (!wil->vring_tx[i].va) return i; @@ -391,7 +393,6 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } - } /* TODO: check order here!!! Erez code is different */ @@ -436,6 +437,7 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); + if (0 == left) { wil_err(wil, "Firmware not ready\n"); return -ETIME; @@ -461,9 +463,8 @@ int wil_reset(struct wil6210_priv *wil) wil6210_disconnect(wil, NULL); wil->status = 0; /* prevent NAPI from being scheduled */ - if (test_bit(wil_status_napi_en, &wil->status)) { + if (test_bit(wil_status_napi_en, &wil->status)) napi_synchronize(&wil->napi_rx); - } if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 97c6a24..2b57069 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -183,6 +183,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, int size, u16 ssn) { struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) return NULL; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2cc3569..ce0c4ba 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -52,6 +52,7 @@ static inline int wil_vring_is_full(struct vring *vring) { return wil_vring_next_tail(vring) == vring->swhead; } + /* * Available space in Tx Vring */ @@ -110,7 +111,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) * we can use any */ for (i = 0; i < vring->size; i++) { - volatile struct vring_tx_desc *_d = &(vring->va[i].tx); + volatile struct vring_tx_desc *_d = &vring->va[i].tx; + _d->dma.status = TX_DMA_STATUS_DU; } @@ -125,6 +127,7 @@ static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, { dma_addr_t pa = wil_desc_addr(&d->dma.addr); u16 dmalen = le16_to_cpu(d->dma.length); + switch (ctx->mapped_as) { case wil_mapped_as_single: dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); @@ -203,11 +206,12 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, struct device *dev = wil_to_dev(wil); unsigned int sz = RX_BUF_LEN; struct vring_rx_desc dd, *d = ⅆ - volatile struct vring_rx_desc *_d = &(vring->va[i].rx); + volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; /* TODO align */ struct sk_buff *skb = dev_alloc_skb(sz + headroom); + if (unlikely(!skb)) return -ENOMEM; @@ -286,9 +290,11 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, */ int len = min_t(int, 8 + sizeof(phy_data), wil_rxdesc_phy_length(d)); + if (len > 8) { void *p = skb_tail_pointer(skb); void *pa = PTR_ALIGN(p, 8); + if (skb_tailroom(skb) >= len + (pa - p)) { phy_length = len - 8; memcpy(phy_data, pa, phy_length); @@ -384,13 +390,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, int cid; struct wil_net_stats *stats; - BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); if (wil_vring_is_empty(vring)) return NULL; - _d = &(vring->va[vring->swhead].rx); + _d = &vring->va[vring->swhead].rx; if (!(_d->dma.status & RX_DMA_STATUS_DU)) { /* it is not error, we just reached end of Rx done area */ return NULL; @@ -544,7 +549,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) [GRO_NORMAL] = "GRO_NORMAL", [GRO_DROP] = "GRO_DROP", }; - wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n", + wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", len, gro_res_str[rc]); } } @@ -585,7 +590,6 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) else wil_netif_rx_any(skb, ndev); } - } wil_rx_refill(wil, v->size); } @@ -733,6 +737,7 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { if (wil->vring2cid_tid[i][0] == cid) { struct vring *v = &wil->vring_tx[i]; + wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n", __func__, eth->h_dest, i); if (v->va) { @@ -752,6 +757,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil, { struct ethhdr *eth = (void *)skb->data; int cid = wil->vring2cid_tid[vring_index][0]; + memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); } @@ -762,7 +768,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * duplicate skb and send it to other active vrings */ static struct vring *wil_tx_bcast(struct wil6210_priv *wil, - struct sk_buff *skb) + struct sk_buff *skb) { struct vring *v, *v2; struct sk_buff *skb2; @@ -845,8 +851,8 @@ void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) } static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, - struct vring_tx_desc *d, - struct sk_buff *skb) + struct vring_tx_desc *d, + struct sk_buff *skb) { int protocol; @@ -914,10 +920,9 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, 1 + nr_frags); return -ENOMEM; } - _d = &(vring->va[i].tx); + _d = &vring->va[i].tx; - pa = dma_map_single(dev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); + pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), skb->data, &pa); @@ -946,10 +951,11 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); + i = (swhead + f + 1) % vring->size; - _d = &(vring->va[i].tx); + _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), - DMA_TO_DEVICE); + DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, pa))) goto dma_error; vring->ctx[i].mapped_as = wil_mapped_as_page; @@ -994,7 +1000,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, i = (swhead + f) % vring->size; ctx = &vring->ctx[i]; - _d = &(vring->va[i].tx); + _d = &vring->va[i].tx; *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; wil_txdesc_unmap(dev, d, ctx); @@ -1008,7 +1014,6 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } - netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); @@ -1036,15 +1041,15 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) pr_once_fw = false; /* find vring */ - if (is_unicast_ether_addr(eth->h_dest)) { + if (is_unicast_ether_addr(eth->h_dest)) vring = wil_find_tx_vring(wil, skb); - } else { + else vring = wil_tx_bcast(wil, skb); - } if (!vring) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } + /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index a1ac4f8..979edf2 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -237,7 +237,6 @@ struct vring_tx_mac { #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2 #define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */ - #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */ @@ -246,7 +245,6 @@ struct vring_tx_mac { #define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */ - #define TX_DMA_STATUS_DU BIT(0) struct vring_tx_dma { @@ -347,7 +345,6 @@ struct vring_rx_mac { #define RX_DMA_ERROR_L3_ERR BIT(4) #define RX_DMA_ERROR_L4_ERR BIT(5) - /* Status field */ #define RX_DMA_STATUS_DU BIT(0) #define RX_DMA_STATUS_ERROR BIT(2) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 063beaf..5f20fab 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -164,6 +164,7 @@ struct fw_map { u32 host; /* PCI/Host address - BAR0 + 0x880000 */ const char *name; /* for debugfs */ }; + /* array size should be in sync with actual definition in the wmi.c */ extern const struct fw_map fw_mapping[7]; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 490c278..97909f0 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -157,6 +157,7 @@ int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, struct wil6210_mbox_hdr *hdr) { void __iomem *src = wmi_buffer(wil, ptr); + if (!src) return -EINVAL; @@ -278,6 +279,7 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wmi_ready_event *evt = d; + wil->fw_version = le32_to_cpu(evt->sw_version); wil->n_mids = evt->numof_additional_mids; @@ -708,6 +710,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->id); u32 tstamp = le32_to_cpu(wmi->timestamp); + wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n", id, wmi->mid, tstamp); trace_wil6210_wmi_event(wmi, &wmi[1], @@ -953,6 +956,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) int rc; u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); + if (!cmd) return -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 061618c..27b9743 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -179,7 +179,6 @@ enum wmi_crypto_type { WMI_CRYPT_AES_GCMP = 0x20, }; - enum wmi_connect_ctrl_flag_bits { WMI_CONNECT_ASSOC_POLICY_USER = 0x0001, WMI_CONNECT_SEND_REASSOC = 0x0002, @@ -219,7 +218,6 @@ struct wmi_disconnect_sta_cmd { __le16 disconnect_reason; } __packed; - /* * WMI_SET_PMK_CMDID */ @@ -234,7 +232,6 @@ struct wmi_set_pmk_cmd { u8 pmk[WMI_PMK_LEN]; } __packed; - /* * WMI_SET_PASSPHRASE_CMDID */ @@ -273,7 +270,6 @@ struct wmi_delete_cipher_key_cmd { u8 mac[WMI_MAC_LEN]; } __packed; - /* * WMI_START_SCAN_CMDID * @@ -325,7 +321,6 @@ struct wmi_probed_ssid_cmd { u8 ssid[WMI_MAX_SSID_LEN]; } __packed; - /* * WMI_SET_APPIE_CMDID * Add Application specified IE to a management frame @@ -351,7 +346,6 @@ struct wmi_set_appie_cmd { u8 ie_info[0]; } __packed; - /* * WMI_PXMT_RANGE_CFG_CMDID */ @@ -380,7 +374,6 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; - /* * WMI_RF_RX_TEST_CMDID */ @@ -426,7 +419,6 @@ struct wmi_bcon_ctrl_cmd { u8 disable_sec; } __packed; - /******* P2P ***********/ /* @@ -797,7 +789,6 @@ struct wmi_temp_sense_cmd { __le32 measure_marlon_r_en; } __packed; - /* * WMI Events */ @@ -887,7 +878,6 @@ enum wmi_event_id { * Events data structures */ - enum wmi_fw_status { WMI_FW_STATUS_SUCCESS, WMI_FW_STATUS_FAILURE, @@ -1038,8 +1028,8 @@ struct wmi_disconnect_event { __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ u8 bssid[WMI_MAC_LEN]; /* set if known */ u8 disconnect_reason; /* see wmi_disconnect_reason */ - u8 assoc_resp_len; /* not in use */ - u8 assoc_info[0]; /* not in use */ + u8 assoc_resp_len; /* not used */ + u8 assoc_info[0]; /* not used */ } __packed; /* @@ -1081,7 +1071,6 @@ struct wmi_delba_event { __le16 reason; } __packed; - /* * WMI_VRING_CFG_DONE_EVENTID */ @@ -1147,7 +1136,6 @@ struct wmi_data_port_open_event { u8 reserved[3]; } __packed; - /* * WMI_GET_PCP_CHANNEL_EVENTID */ @@ -1156,7 +1144,6 @@ struct wmi_get_pcp_channel_event { u8 reserved[3]; } __packed; - /* * WMI_PORT_ALLOCATED_EVENTID */ @@ -1260,7 +1247,6 @@ struct wmi_rx_mgmt_info { u8 channel; /* From Radio MNGR */ } __packed; - /* * WMI_TX_MGMT_PACKET_EVENTID */ -- cgit v0.10.2 From f772ebfb941a58af9e7adf9117bc0bb4c7d22f28 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:35 +0300 Subject: wil6210: platform specific module New module (wil_platform) for handling platform specific tasks Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index ce8c038..481680a 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -39,3 +39,12 @@ config WIL6210_TRACING option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems. + +config WIL6210_PLATFORM_MSM + bool "wil6210 MSM platform specific support" + depends on WIL6210 + depends on ARCH_MSM + default y + ---help--- + Say Y here to enable wil6210 driver support for MSM + platform specific features diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index dc788a1..a471d74 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -12,6 +12,8 @@ wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o +wil6210-y += wil_platform.o +wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 4a884b4..8afd8a2 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -603,6 +603,10 @@ static int __wil_up(struct wil6210_priv *wil) napi_enable(&wil->napi_tx); set_bit(wil_status_napi_en, &wil->status); + if (wil->platform_ops.bus_request) + wil->platform_ops.bus_request(wil->platform_handle, + WIL_MAX_BUS_REQUEST_KBPS); + return 0; } @@ -621,6 +625,9 @@ static int __wil_down(struct wil6210_priv *wil) { WARN_ON(!mutex_is_locked(&wil->mutex)); + if (wil->platform_ops.bus_request) + wil->platform_ops.bus_request(wil->platform_handle, 0); + clear_bit(wil_status_napi_en, &wil->status); napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 38dcbea..968f0d6 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -180,6 +180,10 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil->board = board; wil6210_clear_irq(wil); + + wil->platform_handle = + wil_platform_init(&pdev->dev, &wil->platform_ops); + /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { @@ -204,6 +208,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus_disable: wil_if_pcie_disable(wil); if_free: + if (wil->platform_ops.uninit) + wil->platform_ops.uninit(wil->platform_handle); wil_if_free(wil); err_iounmap: pci_iounmap(pdev, csr); @@ -223,6 +229,8 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil6210_debugfs_remove(wil); wil_if_pcie_disable(wil); wil_if_remove(wil); + if (wil->platform_ops.uninit) + wil->platform_ops.uninit(wil->platform_handle); wil_if_free(wil); pci_iounmap(pdev, csr); pci_release_region(pdev, 0); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 5f20fab..d2e710e 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -21,10 +21,14 @@ #include #include #include +#include "wil_platform.h" + #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" +#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ + struct wil_board { int board; #define WIL_BOARD_MARLON (1) @@ -437,6 +441,9 @@ struct wil6210_priv { /* debugfs */ struct dentry *debug; struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)]; + + void *platform_handle; + struct wil_platform_ops platform_ops; }; #define wil_to_wiphy(i) (i->wdev->wiphy) diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c new file mode 100644 index 0000000..8f1d78f --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "linux/device.h" +#include "wil_platform.h" + +#ifdef CONFIG_WIL6210_PLATFORM_MSM +#include "wil_platform_msm.h" +#endif + +/** + * wil_platform_init() - wil6210 platform module init + * + * The function must be called before all other functions in this module. + * It returns a handle which is used with the rest of the API + * + */ +void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) +{ + void *handle = NULL; + + if (!ops) { + dev_err(dev, "Invalid parameter. Cannot init platform module\n"); + return NULL; + } + +#ifdef CONFIG_WIL6210_PLATFORM_MSM + handle = wil_platform_msm_init(dev, ops); + if (handle) + return handle; +#endif + + /* other platform specific init functions should be called here */ + + return handle; +} diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h new file mode 100644 index 0000000..158c73b --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WIL_PLATFORM_H__ +#define __WIL_PLATFORM_H__ + +struct device; + +/** + * struct wil_platform_ops - wil platform module callbacks + */ +struct wil_platform_ops { + int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */); + int (*suspend)(void *handle); + int (*resume)(void *handle); + void (*uninit)(void *handle); +}; + +void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops); + +#endif /* __WIL_PLATFORM_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c new file mode 100644 index 0000000..b354a74 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "wil_platform.h" +#include "wil_platform_msm.h" + +/** + * struct wil_platform_msm - wil6210 msm platform module info + * + * @dev: device object + * @msm_bus_handle: handle for using msm_bus API + * @pdata: bus scale info retrieved from DT + */ +struct wil_platform_msm { + struct device *dev; + uint32_t msm_bus_handle; + struct msm_bus_scale_pdata *pdata; +}; + +#define KBTOB(a) (a * 1000ULL) + +/** + * wil_platform_get_pdata() - Generate bus client data from device tree + * provided by clients. + * + * dev: device object + * of_node: Device tree node to extract information from + * + * The function returns a valid pointer to the allocated bus-scale-pdata + * if the vectors were correctly read from the client's device node. + * Any error in reading or parsing the device node will return NULL + * to the caller. + */ +static struct msm_bus_scale_pdata *wil_platform_get_pdata( + struct device *dev, + struct device_node *of_node) +{ + struct msm_bus_scale_pdata *pdata; + struct msm_bus_paths *usecase; + int i, j, ret, len; + unsigned int num_usecases, num_paths, mem_size; + const uint32_t *vec_arr; + struct msm_bus_vectors *vectors; + + /* first read num_usecases and num_paths so we can calculate + * amount of memory to allocate + */ + ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases", + &num_usecases); + if (ret) { + dev_err(dev, "Error: num-usecases not found\n"); + return NULL; + } + + ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths", + &num_paths); + if (ret) { + dev_err(dev, "Error: num_paths not found\n"); + return NULL; + } + + /* pdata memory layout: + * msm_bus_scale_pdata + * msm_bus_paths[num_usecases] + * msm_bus_vectors[num_usecases][num_paths] + */ + mem_size = sizeof(struct msm_bus_scale_pdata) + + sizeof(struct msm_bus_paths) * num_usecases + + sizeof(struct msm_bus_vectors) * num_usecases * num_paths; + + pdata = kzalloc(mem_size, GFP_KERNEL); + if (!pdata) + return NULL; + + ret = of_property_read_string(of_node, "qcom,msm-bus,name", + &pdata->name); + if (ret) { + dev_err(dev, "Error: Client name not found\n"); + goto err; + } + + if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) { + pdata->active_only = 1; + } else { + dev_info(dev, "active_only flag absent.\n"); + dev_info(dev, "Using dual context by default\n"); + } + + pdata->num_usecases = num_usecases; + pdata->usecase = (struct msm_bus_paths *)(pdata + 1); + + vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len); + if (vec_arr == NULL) { + dev_err(dev, "Error: Vector array not found\n"); + goto err; + } + + if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) { + dev_err(dev, "Error: Length-error on getting vectors\n"); + goto err; + } + + vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases); + for (i = 0; i < num_usecases; i++) { + usecase = &pdata->usecase[i]; + usecase->num_paths = num_paths; + usecase->vectors = &vectors[i]; + + for (j = 0; j < num_paths; j++) { + int index = ((i * num_paths) + j) * 4; + + usecase->vectors[j].src = be32_to_cpu(vec_arr[index]); + usecase->vectors[j].dst = + be32_to_cpu(vec_arr[index + 1]); + usecase->vectors[j].ab = (uint64_t) + KBTOB(be32_to_cpu(vec_arr[index + 2])); + usecase->vectors[j].ib = (uint64_t) + KBTOB(be32_to_cpu(vec_arr[index + 3])); + } + } + + return pdata; + +err: + kfree(pdata); + + return NULL; +} + +/* wil_platform API (callbacks) */ + +static int wil_platform_bus_request(void *handle, + uint32_t kbps /* KBytes/Sec */) +{ + int rc, i; + struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; + int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */ + struct msm_bus_paths *usecase; + uint32_t usecase_kbps; + uint32_t min_kbps = ~0; + + /* find the lowest usecase that is bigger than requested kbps */ + for (i = 0; i < msm->pdata->num_usecases; i++) { + usecase = &msm->pdata->usecase[i]; + /* assume we have single path (vectors[0]). If we ever + * have multiple paths, need to define the behavior */ + usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000); + if (usecase_kbps >= kbps && usecase_kbps < min_kbps) { + min_kbps = usecase_kbps; + vote = i; + } + } + + rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote); + if (rc) + dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n", + kbps, vote, rc); + else + /* TOOD: remove */ + dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n", + kbps, vote); + + return rc; +} + +static void wil_platform_uninit(void *handle) +{ + struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; + + dev_info(msm->dev, "wil_platform_uninit\n"); + + if (msm->msm_bus_handle) + msm_bus_scale_unregister_client(msm->msm_bus_handle); + + kfree(msm->pdata); + kfree(msm); +} + +static int wil_platform_msm_bus_register(struct wil_platform_msm *msm, + struct device_node *node) +{ + msm->pdata = wil_platform_get_pdata(msm->dev, node); + if (!msm->pdata) { + dev_err(msm->dev, "Failed getting DT info\n"); + return -EINVAL; + } + + msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata); + if (!msm->msm_bus_handle) { + dev_err(msm->dev, "Failed msm_bus registration\n"); + return -EINVAL; + } + + dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n", + msm->msm_bus_handle); + + return 0; +} + +/** + * wil_platform_msm_init() - wil6210 msm platform module init + * + * The function must be called before all other functions in this module. + * It returns a handle which is used with the rest of the API + * + */ +void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops) +{ + struct device_node *of_node; + struct wil_platform_msm *msm; + int rc; + + of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210"); + if (!of_node) { + /* this could mean non-msm platform */ + dev_err(dev, "DT node not found\n"); + return NULL; + } + + msm = kzalloc(sizeof(*msm), GFP_KERNEL); + if (!msm) + return NULL; + + msm->dev = dev; + + /* register with msm_bus module for scaling requests */ + rc = wil_platform_msm_bus_register(msm, of_node); + if (rc) + goto cleanup; + + memset(ops, 0, sizeof(*ops)); + ops->bus_request = wil_platform_bus_request; + ops->uninit = wil_platform_uninit; + + return (void *)msm; + +cleanup: + kfree(msm); + return NULL; +} diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h new file mode 100644 index 0000000..2f2229e --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WIL_PLATFORM__MSM_H__ +#define __WIL_PLATFORM_MSM_H__ + +#include "wil_platform.h" + +void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops); + +#endif /* __WIL_PLATFORM__MSM_H__ */ -- cgit v0.10.2 From 9cf10d623e4fc7d3d8bb6d6ce835e10933b3b114 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:36 +0300 Subject: wil6210: add more debug printouts added misc printouts in some init/uninit functions for better traceability Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index cba04e5..c8c9852 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -782,8 +782,8 @@ static void wil_wiphy_init(struct wiphy *wiphy) */ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", - __func__, wiphy->flags); + dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", + __func__, wiphy->flags); wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | @@ -804,6 +804,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev) int rc = 0; struct wireless_dev *wdev; + dev_dbg(dev, "%s()\n", __func__); + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); if (!wdev) return ERR_PTR(-ENOMEM); @@ -836,6 +838,8 @@ void wil_wdev_free(struct wil6210_priv *wil) { struct wireless_dev *wdev = wil_to_wdev(wil); + dev_dbg(wil_to_dev(wil), "%s()\n", __func__); + if (!wdev) return; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 6411651..331d0dc 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -528,6 +528,9 @@ void wil6210_clear_irq(struct wil6210_priv *wil) int wil6210_init_irq(struct wil6210_priv *wil, int irq) { int rc; + + wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi); + if (wil->n_msi == 3) rc = wil6210_request_3msi(wil, irq); else @@ -545,6 +548,8 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq) void wil6210_fini_irq(struct wil6210_priv *wil, int irq) { + wil_dbg_misc(wil, "%s()\n", __func__); + wil6210_disable_irq(wil); free_irq(irq, wil); if (wil->n_msi == 3) { diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8afd8a2..696be3e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -301,12 +301,16 @@ int wil_priv_init(struct wil6210_priv *wil) void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) { + wil_dbg_misc(wil, "%s()\n", __func__); + del_timer_sync(&wil->connect_timer); _wil6210_disconnect(wil, bssid); } void wil_priv_deinit(struct wil6210_priv *wil) { + wil_dbg_misc(wil, "%s()\n", __func__); + del_timer_sync(&wil->scan_timer); cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); @@ -457,6 +461,8 @@ int wil_reset(struct wil6210_priv *wil) { int rc; + wil_dbg_misc(wil, "%s()\n", __func__); + WARN_ON(!mutex_is_locked(&wil->mutex)); cancel_work_sync(&wil->disconnect_worker); @@ -614,6 +620,8 @@ int wil_up(struct wil6210_priv *wil) { int rc; + wil_dbg_misc(wil, "%s()\n", __func__); + mutex_lock(&wil->mutex); rc = __wil_up(wil); mutex_unlock(&wil->mutex); @@ -650,6 +658,8 @@ int wil_down(struct wil6210_priv *wil) { int rc; + wil_dbg_misc(wil, "%s()\n", __func__); + mutex_lock(&wil->mutex); rc = __wil_down(wil); mutex_unlock(&wil->mutex); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index a44c2b6..a995d9d 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -22,6 +22,8 @@ static int wil_open(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + wil_dbg_misc(wil, "%s()\n", __func__); + return wil_up(wil); } @@ -29,6 +31,8 @@ static int wil_stop(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + wil_dbg_misc(wil, "%s()\n", __func__); + return wil_down(wil); } @@ -121,6 +125,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) wil->csr = csr; wil->wdev = wdev; + wil_dbg_misc(wil, "%s()\n", __func__); + rc = wil_priv_init(wil); if (rc) { dev_err(dev, "wil_priv_init failed\n"); @@ -169,6 +175,8 @@ void wil_if_free(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); + wil_dbg_misc(wil, "%s()\n", __func__); + if (!ndev) return; @@ -185,6 +193,8 @@ int wil_if_add(struct wil6210_priv *wil) struct net_device *ndev = wil_to_ndev(wil); int rc; + wil_dbg_misc(wil, "%s()\n", __func__); + rc = register_netdev(ndev); if (rc < 0) { dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); @@ -200,5 +210,7 @@ void wil_if_remove(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); + wil_dbg_misc(wil, "%s()\n", __func__); + unregister_netdev(ndev); } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 968f0d6..d2a1ca2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -41,6 +41,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) */ int msi_only = pdev->msi_enabled; + wil_dbg_misc(wil, "%s()\n", __func__); + pdev->msi_enabled = 0; pci_set_master(pdev); @@ -107,6 +109,8 @@ static int wil_if_pcie_disable(struct wil6210_priv *wil) { struct pci_dev *pdev = wil->pdev; + wil_dbg_misc(wil, "%s()\n", __func__); + pci_clear_master(pdev); /* disable and release IRQ */ wil6210_fini_irq(wil, pdev->irq); @@ -226,6 +230,8 @@ static void wil_pcie_remove(struct pci_dev *pdev) struct wil6210_priv *wil = pci_get_drvdata(pdev); void __iomem *csr = wil->csr; + wil_dbg_misc(wil, "%s()\n", __func__); + wil6210_debugfs_remove(wil); wil_if_pcie_disable(wil); wil_if_remove(wil); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index ce0c4ba..02fd43d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -87,6 +87,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) size_t sz = vring->size * sizeof(vring->va[0]); uint i; + wil_dbg_misc(wil, "%s()\n", __func__); + BUILD_BUG_ON(sizeof(vring->va[0]) != 32); vring->swhead = 0; @@ -599,6 +601,8 @@ int wil_rx_init(struct wil6210_priv *wil) struct vring *vring = &wil->vring_rx; int rc; + wil_dbg_misc(wil, "%s()\n", __func__); + if (vring->va) { wil_err(wil, "Rx ring already allocated\n"); return -EINVAL; @@ -628,6 +632,8 @@ void wil_rx_fini(struct wil6210_priv *wil) { struct vring *vring = &wil->vring_rx; + wil_dbg_misc(wil, "%s()\n", __func__); + if (vring->va) wil_vring_free(wil, vring, 0); } @@ -662,6 +668,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, struct vring *vring = &wil->vring_tx[id]; struct vring_tx_data *txdata = &wil->vring_tx_data[id]; + wil_dbg_misc(wil, "%s()\n", __func__); + if (vring->va) { wil_err(wil, "Tx ring [%d] already allocated\n", id); rc = -EINVAL; @@ -711,6 +719,8 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) if (!vring->va) return; + wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); + /* make sure NAPI won't touch this vring */ wil->vring_tx_data[id].enabled = 0; if (test_bit(wil_status_napi_en, &wil->status)) -- cgit v0.10.2 From 69778059734b38ea6f4aa9d31262ad03e77b1b06 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:37 +0300 Subject: wil6210: fix for memory corruption while insmod After setting interrupt handler, driver enabled interrupts. This caused stale (old) HW interrupts to fire before driver is fully initialized. The fix is to enable interrupts only when driver is fully initialized and after FW/HW reset (to prevent any stale interrupts) Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 331d0dc..58ddcc9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -538,12 +538,7 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq) wil6210_thread_irq, wil->n_msi ? 0 : IRQF_SHARED, WIL_NAME, wil); - if (rc) - return rc; - - wil6210_enable_irq(wil); - - return 0; + return rc; } void wil6210_fini_irq(struct wil6210_priv *wil, int irq) -- cgit v0.10.2 From f172b56309fbc4835b3f258df6865309dc02e80c Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:38 +0300 Subject: wil6210: fix for memory corruption upon rmmod Driver disabled PCI master before making sure HW is idle. This caused memory corruption in case HW access system memory after PCI master got disabled. The fix is to change uninit sequence. Make sure FW/HW is idle before disabling PCI Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 696be3e..22e9b8a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -20,6 +20,10 @@ #include "wil6210.h" #include "txrx.h" +#include "wmi.h" + +#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 +#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 static bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); @@ -631,6 +635,9 @@ int wil_up(struct wil6210_priv *wil) static int __wil_down(struct wil6210_priv *wil) { + int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS / + WAIT_FOR_DISCONNECT_INTERVAL_MS; + WARN_ON(!mutex_is_locked(&wil->mutex)); if (wil->platform_ops.bus_request) @@ -648,7 +655,24 @@ static int __wil_down(struct wil6210_priv *wil) wil->scan_request = NULL; } - wil6210_disconnect(wil, NULL); + if (test_bit(wil_status_fwconnected, &wil->status) || + test_bit(wil_status_fwconnecting, &wil->status)) + wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); + + /* make sure wil is idle (not connected) */ + mutex_unlock(&wil->mutex); + while (iter--) { + int idle = !test_bit(wil_status_fwconnected, &wil->status) && + !test_bit(wil_status_fwconnecting, &wil->status); + if (idle) + break; + msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS); + } + mutex_lock(&wil->mutex); + + if (!iter) + wil_err(wil, "timeout waiting for idle FW/HW\n"); + wil_rx_fini(wil); return 0; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d2a1ca2..264c0f0 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -233,8 +233,8 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil_dbg_misc(wil, "%s()\n", __func__); wil6210_debugfs_remove(wil); - wil_if_pcie_disable(wil); wil_if_remove(wil); + wil_if_pcie_disable(wil); if (wil->platform_ops.uninit) wil->platform_ops.uninit(wil->platform_handle); wil_if_free(wil); -- cgit v0.10.2 From 871d8c4bbb0f23c29a21b63b1801071766f69b51 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:39 +0300 Subject: wil6210: fix usage of print_hex_dump_debug When CONFIG_DYNAMIC_DEBUG is not defined, print_hex_dump_debug is mapped directly to print_hex_dump which might cause printout to exist all the time Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index d2e710e..e51531b 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -468,6 +468,7 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +#if defined(CONFIG_DYNAMIC_DEBUG) #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ print_hex_dump_debug("DBG[TXRX]" prefix_str,\ @@ -479,6 +480,12 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...); print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) +#else +#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) +#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) +#endif void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); -- cgit v0.10.2 From 8c86f757b1c0a154cb8939b0fff3aaa1ff9b1910 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:40 +0300 Subject: wil6210: fix race condition of disconnect while BACK event This race condition was causing double free of tid_ampdu_rx structures Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 97909f0..c71657b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -597,16 +597,18 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, return; } + mutex_lock(&wil->mutex); + cid = wil->vring2cid_tid[evt->ringid][0]; if (cid >= WIL6210_MAX_CID) { wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); - return; + goto out; } sta = &wil->sta[cid]; if (sta->status == wil_sta_unused) { wil_err(wil, "CID %d unused\n", cid); - return; + goto out; } wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); @@ -618,6 +620,9 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, evt->agg_wsize, 0); } + +out: + mutex_unlock(&wil->mutex); } static const struct { -- cgit v0.10.2 From 4cf99c93d24f9cdd338ab23cd671e949ee6ca1bd Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:41 +0300 Subject: wil6210: modify confusing printout When WMI event received when driver not ready to accept it, the printed error message is misleading and hints that HW is stuck. Modify the error message to make it clearer Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c71657b..ad48f14 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -660,7 +660,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) unsigned n; if (!test_bit(wil_status_reset_done, &wil->status)) { - wil_err(wil, "Reset not completed\n"); + wil_err(wil, "Reset in progress. Cannot handle WMI event\n"); return; } -- cgit v0.10.2 From ec81b5adf42e02560b3b05a0c8897451cd3d8b29 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:42 +0300 Subject: wil6210: fix race condition between BACK event and Rx data While handling Rx packet, BACK event arrives and frees tid_ampdu_rx array. This causes kernel panic while accessing already freed spinlock The fix is to remove tid_ampdu_rx[]'s spinlock and instead use single sta's spinlock to guard the whole tid_ampdu_rx array. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index e1f9276..21dc437 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1059,6 +1059,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; int i, tid; + unsigned long flags; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -1079,6 +1080,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { + spin_lock_irqsave(&p->tid_rx_lock, flags); for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; @@ -1087,6 +1089,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) wil_print_rxtid(s, r); } } + spin_unlock_irqrestore(&p->tid_rx_lock, flags); } } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 22e9b8a..d2f2c1e 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -95,9 +95,16 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) } for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + struct wil_tid_ampdu_rx *r; + unsigned long flags; + + spin_lock_irqsave(&sta->tid_rx_lock, flags); + + r = sta->tid_rx[i]; sta->tid_rx[i] = NULL; wil_tid_ampdu_rx_free(wil, r); + + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); } for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (wil->vring2cid_tid[i][0] == cid) @@ -267,9 +274,13 @@ static void wil_connect_worker(struct work_struct *work) int wil_priv_init(struct wil6210_priv *wil) { + uint i; + wil_dbg_misc(wil, "%s()\n", __func__); memset(wil->sta, 0, sizeof(wil->sta)); + for (i = 0; i < WIL6210_MAX_CID; i++) + spin_lock_init(&wil->sta[i].tid_rx_lock); mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 2b57069..489cb73 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -98,22 +98,25 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) int mid = wil_rxdesc_mid(d); u16 seq = wil_rxdesc_seq(d); struct wil_sta_info *sta = &wil->sta[cid]; - struct wil_tid_ampdu_rx *r = sta->tid_rx[tid]; + struct wil_tid_ampdu_rx *r; u16 hseq; int index; + unsigned long flags; wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", mid, cid, tid, seq); + spin_lock_irqsave(&sta->tid_rx_lock, flags); + + r = sta->tid_rx[tid]; if (!r) { + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); wil_netif_rx_any(skb, ndev); return; } hseq = r->head_seq_num; - spin_lock(&r->reorder_lock); - /** Due to the race between WMI events, where BACK establishment * reported, and data Rx, few packets may be pass up before reorder * buffer get allocated. Catch up by pretending SSN is what we @@ -176,7 +179,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) wil_reorder_release(wil, r); out: - spin_unlock(&r->reorder_lock); + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); } struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, @@ -198,7 +201,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, return NULL; } - spin_lock_init(&r->reorder_lock); r->ssn = ssn; r->head_seq_num = ssn; r->buf_size = size; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e51531b..1b11934 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -318,18 +318,12 @@ struct pci_dev; * @timeout: reset timer value (in TUs). * @dialog_token: dialog token for aggregation session * @rcu_head: RCU head used for freeing this struct - * @reorder_lock: serializes access to reorder buffer, see below. * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. * - * The @reorder_lock is used to protect the members of this - * struct, except for @timeout, @buf_size and @dialog_token, - * which are constant across the lifetime of the struct (the - * dialog token being used only for debugging). */ struct wil_tid_ampdu_rx { - spinlock_t reorder_lock; /* see above */ struct sk_buff **reorder_buf; unsigned long *reorder_time; struct timer_list session_timer; @@ -378,6 +372,7 @@ struct wil_sta_info { bool data_port_open; /* can send any data, not only EAPOL */ /* Rx BACK */ struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM]; + spinlock_t tid_rx_lock; /* guarding tid_rx array */ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)]; unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)]; }; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index ad48f14..c3682c3a 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -613,9 +613,17 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r = sta->tid_rx[i]; + struct wil_tid_ampdu_rx *r; + unsigned long flags; + + spin_lock_irqsave(&sta->tid_rx_lock, flags); + + r = sta->tid_rx[i]; sta->tid_rx[i] = NULL; wil_tid_ampdu_rx_free(wil, r); + + spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, evt->agg_wsize, 0); -- cgit v0.10.2 From ac4acdb7af7b5f1f197e7c3fdce13b6aa72c29c6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:43 +0300 Subject: wil6210: send connect request IEs to FW also for non-secure connection Driver is sending connect request IEs to FW only for secure connection and ignores them for non-secure connection. This is fixed by always sending the IEs to FW upon connect request Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c8c9852..c1ff330 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -379,22 +379,22 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, sme->ie_len); goto out; } - /* - * For secure assoc, send: - * (1) WMI_DELETE_CIPHER_KEY_CMD - * (2) WMI_SET_APPIE_CMD - */ + /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); goto out; } - /* WMI_SET_APPIE_CMD */ - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); - if (rc) { - wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); - goto out; - } + } + + /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info + * elements. Send it also in case it's empty, to erase previously set + * ies in FW. + */ + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); + if (rc) { + wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); + goto out; } /* WMI_CONNECT_CMD */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c3682c3a..789c316 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -972,6 +972,8 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) if (!cmd) return -ENOMEM; + if (!ie) + ie_len = 0; cmd->mgmt_frm_type = type; /* BUG: FW API define ieLen as u8. Will fix FW */ -- cgit v0.10.2 From 1bd922fce29168b8a7d5b53c7be89de87381896b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:44 +0300 Subject: wil6210: add change_beacon() driver callback This allows updating IEs (e.g. from hostapd) when AP is already started Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c1ff330..61eaf20 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -640,6 +640,45 @@ static int wil_fix_bcon(struct wil6210_priv *wil, return rc; } +static int wil_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_beacon_data *bcon) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil_dbg_misc(wil, "%s()\n", __func__); + + if (wil_fix_bcon(wil, bcon)) { + wil_dbg_misc(wil, "Fixed bcon\n"); + wil_print_bcon_data(bcon); + } + + /* FW do not form regular beacon, so bcon IE's are not set + * For the DMG bcon, when it will be supported, bcon IE's will + * be reused; add something like: + * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, + * bcon->beacon_ies); + */ + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, + bcon->proberesp_ies_len, + bcon->proberesp_ies); + if (rc) { + wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + return rc; + } + + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, + bcon->assocresp_ies_len, + bcon->assocresp_ies); + if (rc) { + wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); + return rc; + } + + return 0; +} + static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) @@ -764,6 +803,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .del_key = wil_cfg80211_del_key, .set_default_key = wil_cfg80211_set_default_key, /* AP mode */ + .change_beacon = wil_cfg80211_change_beacon, .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, -- cgit v0.10.2 From e0106adade2dd16fb776f53f25ffe50da0793f3d Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:45 +0300 Subject: wil6210: enlarge TX/RX buffer length HW supports upto 2304 packet size on the air. HW is responsible for adding (Tx) or removing (Rx) the following headers: 802.11 hdr: 26B SNAP: 8B CRC: 4B Security (optional): 24B HW adds max 62B to the payload passed from driver. It means driver can use max packet size of 2304-62 = 2242B Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index a995d9d..1c0c77d 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -17,6 +17,7 @@ #include #include "wil6210.h" +#include "txrx.h" static int wil_open(struct net_device *ndev) { @@ -40,8 +41,10 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu) { struct wil6210_priv *wil = ndev_to_wil(ndev); - if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG) + if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) { + wil_err(wil, "invalid MTU %d\n", new_mtu); return -EINVAL; + } wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu); ndev->mtu = new_mtu; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 02fd43d..2936ef0 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -668,7 +668,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, struct vring *vring = &wil->vring_tx[id]; struct vring_tx_data *txdata = &wil->vring_tx_data[id]; - wil_dbg_misc(wil, "%s()\n", __func__); + wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__, + cmd.vring_cfg.tx_sw_ring.max_mpdu_size); if (vring->va) { wil_err(wil, "Tx ring [%d] already allocated\n", id); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 979edf2..de04671 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -20,9 +20,9 @@ #define BUF_SW_OWNED (1) #define BUF_HW_OWNED (0) -/* size of max. Rx packet */ -#define RX_BUF_LEN (2048) -#define TX_BUF_LEN (2048) +/* size of max. Tx/Rx buffers, as supported by FW */ +#define RX_BUF_LEN (2242) +#define TX_BUF_LEN (2242) /* how many bytes to reserve for rtap header? */ #define WIL6210_RTAP_SIZE (128) -- cgit v0.10.2 From 595026472eb74e4b57f5389af8b7c588659df243 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 10 Sep 2014 16:34:46 +0300 Subject: wil6210: introduce separate completion for WMI re-use of wmi_ready for both FW ready event and for wmi_call was causing false "FW not ready" indication in case wmi_call() was invoked while reset took place. add wmi_call completion variable instead of re-using wmi_ready. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d2f2c1e..0857853 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -286,6 +286,7 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->wmi_mutex); init_completion(&wil->wmi_ready); + init_completion(&wil->wmi_call); wil->pending_connect_cid = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); @@ -536,6 +537,7 @@ int wil_reset(struct wil6210_priv *wil) /* init after reset */ wil->pending_connect_cid = -1; reinit_completion(&wil->wmi_ready); + reinit_completion(&wil->wmi_call); wil6210_enable_irq(wil); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 1b11934..f8f9988 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -399,6 +399,7 @@ struct wil6210_priv { struct mutex wmi_mutex; struct wil6210_mbox_ctl mbox_ctl; struct completion wmi_ready; + struct completion wmi_call; u16 wmi_seq; u16 reply_id; /**< wait for this WMI event */ void *reply_buf; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 789c316..bd781c7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -300,7 +300,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, wil_dbg_wmi(wil, "WMI: got FW ready event\n"); set_bit(wil_status_fwready, &wil->status); - /* reuse wmi_ready for the firmware ready indication */ + /* let the reset sequence continue */ complete(&wil->wmi_ready); } @@ -764,8 +764,8 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, wil->reply_id = reply_id; wil->reply_buf = reply; wil->reply_size = reply_size; - remain = wait_for_completion_timeout(&wil->wmi_ready, - msecs_to_jiffies(to_msec)); + remain = wait_for_completion_timeout(&wil->wmi_call, + msecs_to_jiffies(to_msec)); if (0 == remain) { wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n", cmdid, reply_id, to_msec); @@ -1160,7 +1160,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, len - sizeof(*wmi)); } wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id); - complete(&wil->wmi_ready); + complete(&wil->wmi_call); return; } /* unsolicited event */ -- cgit v0.10.2 From 77c91295ea537e454113297f6f6fbdfb9f3e67fa Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:47 +0300 Subject: wil6210: specify max. IE length Expose firmware limit for the max_scan_ie_len; also do actually set IE's for the probe request max_scan_ie_len used to be 0, this blocks scan requests with non-zero IE's Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 61eaf20..6119ecb 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -309,9 +309,23 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } + if (request->ie_len) + print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET, + request->ie, request->ie_len); + else + wil_dbg_misc(wil, "Scan has no IE's\n"); + + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, + request->ie); + if (rc) { + wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc); + goto out; + } + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); +out: if (rc) { del_timer_sync(&wil->scan_timer); wil->scan_request = NULL; @@ -813,6 +827,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) { /* TODO: set real value */ wiphy->max_scan_ssids = 10; + wiphy->max_scan_ie_len = WMI_MAX_IE_LEN; wiphy->max_num_pmkids = 0 /* TODO: */; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | -- cgit v0.10.2 From d00a6367d227199de52b37622c984af8a21a2507 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:48 +0300 Subject: wil6210: fix typo in comment Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 58ddcc9..7d319d9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -506,7 +506,8 @@ free0: return rc; } -/* can't use wil_ioread32_and_clear because ICC value is not ser yet */ + +/* can't use wil_ioread32_and_clear because ICC value is not set yet */ static inline void wil_clear32(void __iomem *addr) { u32 x = ioread32(addr); -- cgit v0.10.2 From e4dbb093de182bb515821105dcdb8f2268bf6ffc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:49 +0300 Subject: wil6210: rename [en|dis]able irq to [un]mask To better reflect real action performed, rename: s/wil6210_disable_irq/wil_mask_irq/ s/wil6210_enable_irq/wil_unmask_irq/ Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 7d319d9..d265e7c 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -135,7 +135,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); } -void wil6210_disable_irq(struct wil6210_priv *wil) +void wil_mask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); @@ -145,7 +145,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil) wil6210_mask_irq_pseudo(wil); } -void wil6210_enable_irq(struct wil6210_priv *wil) +void wil_unmask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); @@ -546,7 +546,7 @@ void wil6210_fini_irq(struct wil6210_priv *wil, int irq) { wil_dbg_misc(wil, "%s()\n", __func__); - wil6210_disable_irq(wil); + wil_mask_irq(wil); free_irq(irq, wil); if (wil->n_msi == 3) { free_irq(irq + 1, wil); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0857853..8443d82 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -496,7 +496,7 @@ int wil_reset(struct wil6210_priv *wil) wil->scan_request = NULL; } - wil6210_disable_irq(wil); + wil_mask_irq(wil); wmi_event_flush(wil); @@ -539,7 +539,7 @@ int wil_reset(struct wil6210_priv *wil) reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); - wil6210_enable_irq(wil); + wil_unmask_irq(wil); /* we just started MAC, wait for FW ready */ rc = wil_wait_for_fw_ready(wil); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f8f9988..a540781 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -532,8 +532,8 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); -void wil6210_disable_irq(struct wil6210_priv *wil); -void wil6210_enable_irq(struct wil6210_priv *wil); +void wil_mask_irq(struct wil6210_priv *wil); +void wil_unmask_irq(struct wil6210_priv *wil); int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie); -- cgit v0.10.2 From 73d839ae503d591bc0dc802490c00935b19250d1 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:50 +0300 Subject: wil6210: fix for oops while stopping interface When interface stopped while running intensive Rx traffic, the following oops observed: [89846.734683] Call trace: [89846.737117] [] dev_gro_receive+0xac/0x358 [89846.742674] [] napi_gro_receive+0x24/0xa4 [89846.748251] [] $x+0xec/0x1f8 [wil6210] wil_netif_rx_any [89846.753547] [] $x+0x34/0x54 [wil6210] wil_release_reorder_frame [89846.758755] [] wil_release_reorder_frames+0x5c/0x78 [wil6210] [89846.766044] [] wil_tid_ampdu_rx_free+0x20/0x48 [wil6210] [89846.772901] [] $x+0x190/0x1e8 [wil6210] [89846.778285] [] wmi_event_worker+0x230/0x2f8 [wil6210] [89846.784865] [] process_one_work+0x278/0x3fc [89846.790591] [] worker_thread+0x200/0x330 [89846.796060] [] kthread+0xac/0xb8 [89846.800836] Code: b940c661 f9406a62 8b010041 f9400026 (f8636882) [89846.807008] ---[ end trace d6fdc17cd27d18f6 ]--- Reason is the following: when removing Rx vring (wil_netdev_ops.ndo_stop -> wil_stop -> wil_down -> __wil_down -> wil_rx_fini), Rx interrupt occurs. It trigger Rx NAPI, calling wil_rx_handle() that reaps (already cleaned) buffer, causing skb referring to garbage memory being set into reorder buffer. Then, network stack trying to access this buffer and fails. Prevent Rx NAPI from being scheduled if device going to stop. Bit wil_status_napi_en reflects NAPI enablement state, check it when triggering Rx NAPI. Testing shows that check for wil_status_napi_en sometimes gets negative, and new error message get printed - in this case kernel oops would be observed. Original oops is no more reproducible. This change requires also changes in the AP flows. Properly enable/disable NAPI for the AP. Make sure Rx VRING is disabled when resetting target. For this, promote __wil_up() and __wil_down() to the module scope, and use it in the relevant flows. Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 6119ecb..f3a31e8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -730,12 +730,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); - rc = wil_reset(wil); - if (rc) - goto out; - - /* Rx VRING. */ - rc = wil_rx_init(wil); + __wil_down(wil); + rc = __wil_up(wil); if (rc) goto out; @@ -743,9 +739,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, if (rc) goto out; - /* MAC address - pre-requisite for other commands */ - wmi_set_mac_address(wil, ndev->dev_addr); - /* IE's */ /* bcon 'head IE's are not relevant for 60g band */ /* @@ -777,7 +770,7 @@ out: static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - int rc = 0; + int rc, rc1; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s()\n", __func__); @@ -786,8 +779,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, rc = wmi_pcp_stop(wil); + __wil_down(wil); + rc1 = __wil_up(wil); + mutex_unlock(&wil->mutex); - return rc; + + return min(rc, rc1); } static int wil_cfg80211_del_station(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index d265e7c..7269bac 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -196,8 +196,13 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil_dbg_irq(wil, "RX done\n"); isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; if (test_bit(wil_status_reset_done, &wil->status)) { - wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); - napi_schedule(&wil->napi_rx); + if (test_bit(wil_status_napi_en, &wil->status)) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, "Got Rx interrupt while " + "stopping interface\n"); + } } else { wil_err(wil, "Got Rx interrupt while in reset\n"); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8443d82..21667e0 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -221,10 +221,8 @@ static void wil_fw_error_worker(struct work_struct *work) case NL80211_IFTYPE_MONITOR: wil_info(wil, "fw error recovery started (try %d)...\n", wil->recovery_count); - wil_reset(wil); - - /* need to re-allocate Rx ring after reset */ - wil_rx_init(wil); + __wil_down(wil); + __wil_up(wil); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: @@ -480,13 +478,12 @@ int wil_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); WARN_ON(!mutex_is_locked(&wil->mutex)); + WARN_ON(test_bit(wil_status_napi_en, &wil->status)); cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL); wil->status = 0; /* prevent NAPI from being scheduled */ - if (test_bit(wil_status_napi_en, &wil->status)) - napi_synchronize(&wil->napi_rx); if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", @@ -575,7 +572,7 @@ void wil_link_off(struct wil6210_priv *wil) netif_carrier_off(ndev); } -static int __wil_up(struct wil6210_priv *wil) +int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; @@ -621,7 +618,7 @@ static int __wil_up(struct wil6210_priv *wil) /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); - + wil_dbg_misc(wil, "NAPI enable\n"); napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); set_bit(wil_status_napi_en, &wil->status); @@ -646,7 +643,7 @@ int wil_up(struct wil6210_priv *wil) return rc; } -static int __wil_down(struct wil6210_priv *wil) +int __wil_down(struct wil6210_priv *wil) { int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS / WAIT_FOR_DISCONNECT_INTERVAL_MS; @@ -656,9 +653,13 @@ static int __wil_down(struct wil6210_priv *wil) if (wil->platform_ops.bus_request) wil->platform_ops.bus_request(wil->platform_handle, 0); - clear_bit(wil_status_napi_en, &wil->status); - napi_disable(&wil->napi_rx); - napi_disable(&wil->napi_tx); + wil_disable_irq(wil); + if (test_and_clear_bit(wil_status_napi_en, &wil->status)) { + napi_disable(&wil->napi_rx); + napi_disable(&wil->napi_tx); + wil_dbg_misc(wil, "NAPI disable\n"); + } + wil_enable_irq(wil); if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 264c0f0..66626a8 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "wil6210.h" @@ -30,6 +31,28 @@ static bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); +void wil_disable_irq(struct wil6210_priv *wil) +{ + int irq = wil->pdev->irq; + + disable_irq(irq); + if (wil->n_msi == 3) { + disable_irq(irq + 1); + disable_irq(irq + 2); + } +} + +void wil_enable_irq(struct wil6210_priv *wil) +{ + int irq = wil->pdev->irq; + + enable_irq(irq); + if (wil->n_msi == 3) { + enable_irq(irq + 1); + enable_irq(irq + 2); + } +} + /* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a540781..0ff0dd9 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -499,7 +499,9 @@ void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_link_on(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); +int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); +int __wil_down(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); @@ -534,6 +536,8 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil_mask_irq(struct wil6210_priv *wil); void wil_unmask_irq(struct wil6210_priv *wil); +void wil_disable_irq(struct wil6210_priv *wil); +void wil_enable_irq(struct wil6210_priv *wil); int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie); -- cgit v0.10.2 From 867fa0d49c8f5d3fd5e0138a754321ffa04903aa Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Wed, 10 Sep 2014 16:34:51 +0300 Subject: wil6210: fix PTR_ERR() usage after initialization to constant Reported by coccinelle: tree: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git master head: 6a5d088a923854569e20eac4f3f569926d5911ec commit: b7cde47009640b88cb3629ee7078a43bc2642459 [18/80] wil6210: convert debugfs to the table mode coccinelle warnings: (new ones prefixed by >>) >> drivers/net/wireless/ath/wil6210/debugfs.c:327:17-24: ERROR: PTR_ERR applied after initialization to constant on line 304 vim +327 drivers/net/wireless/ath/wil6210/debugfs.c 298 struct dentry *dbg, void *base, 299 const struct dbg_off * const tbl) 300 { 301 int i; 302 303 for (i = 0; tbl[i].name; i++) { > 304 struct dentry *f = NULL; 305 306 switch (tbl[i].type) { 307 case doff_u32: 308 f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, 309 base + tbl[i].off); 310 break; 311 case doff_x32: 312 f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, 313 base + tbl[i].off); 314 break; 315 case doff_ulong: 316 f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, 317 dbg, base + tbl[i].off); 318 break; 319 case doff_io32: 320 f = wil_debugfs_create_iomem_x32(tbl[i].name, 321 tbl[i].mode, dbg, 322 base + tbl[i].off); 323 break; 324 } 325 if (IS_ERR_OR_NULL(f)) 326 wil_err(wil, "Create file \"%s\": err %ld\n", > 327 tbl[i].name, PTR_ERR(f)); 328 } 329 } 330 Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 21dc437..eb2204e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -308,7 +308,7 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, int i; for (i = 0; tbl[i].name; i++) { - struct dentry *f = NULL; + struct dentry *f; switch (tbl[i].type) { case doff_u32: @@ -328,6 +328,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, tbl[i].mode, dbg, base + tbl[i].off); break; + default: + f = ERR_PTR(-EINVAL); } if (IS_ERR_OR_NULL(f)) wil_err(wil, "Create file \"%s\": err %ld\n", -- cgit v0.10.2 From cbc775db2e17cc24a9d3b2f14570ec7c1e0923af Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Sep 2014 19:15:56 +0530 Subject: ath9k: Assign offchannel duration properly In multi-channel mode, an offchannel request will be deferred if both contexts are active. The duration of the offchannel operation is calculated but is not stored in the scheduler state. Fix this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 522894b..ae575cb 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -588,10 +588,15 @@ static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { - sc->sched.offchannel_pending = true; - sc->sched.wait_switch = true; if (chandef) ctx->chandef = *chandef; + + sc->sched.offchannel_pending = true; + sc->sched.wait_switch = true; + sc->sched.offchannel_duration = + jiffies_to_usecs(sc->offchannel.duration) + + sc->sched.channel_switch_time; + spin_unlock_bh(&sc->chan_lock); ath_dbg(common, CHAN_CTX, "Set offchannel_pending to true\n"); -- cgit v0.10.2 From d0975edd59b94d8906008cf3c68020a44cc198c5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Sep 2014 19:15:57 +0530 Subject: ath9k: Fix Notice of Absence issues * The index has to incremented only when advertising a new NoA schedule. * Switch to non-periodic NoA when starting a scan operation and multiple channel contexts are active. * Make sure that periodic NoA is advertised again when scan ends. Since the offchannel timer moves the offchannel state to IDLE after the GO operating channel becomes active, use a flag "force_noa_update" to update the NoA contents. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0c071b0..305db1a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -379,6 +379,7 @@ struct ath_chanctx_sched { bool beacon_pending; bool offchannel_pending; bool wait_switch; + bool force_noa_update; enum ath_chanctx_state state; u8 beacon_miss; @@ -595,8 +596,10 @@ struct ath_vif { u32 offchannel_start; u32 offchannel_duration; - u32 periodic_noa_start; - u32 periodic_noa_duration; + /* These are used for both periodic and one-shot */ + u32 noa_start; + u32 noa_duration; + bool periodic_noa; }; struct ath9k_vif_iter_data { diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index ae575cb..ab3d29d 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -310,7 +310,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_chanctx *ctx; u32 tsf_time; u32 beacon_int; - bool noa_changed = false; if (vif) avp = (struct ath_vif *) vif->drv_priv; @@ -372,22 +371,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.switch_start_time = tsf_time; sc->cur_chan->last_beacon = sc->sched.next_tbtt; - /* Prevent wrap-around issues */ - if (avp->periodic_noa_duration && - tsf_time - avp->periodic_noa_start > BIT(30)) - avp->periodic_noa_duration = 0; - - if (ctx->active) { - avp->periodic_noa_start = tsf_time; - avp->periodic_noa_duration = - TU_TO_USEC(cur_conf->beacon_interval) / 2 - - sc->sched.channel_switch_time; - noa_changed = true; - } else if (!ctx->active) { - avp->periodic_noa_duration = 0; - noa_changed = true; - } - /* If at least two consecutive beacons were missed on the STA * chanctx, stay on the STA channel for one extra beacon period, * to resync the timer properly. @@ -395,21 +378,65 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (ctx->active && sc->sched.beacon_miss >= 2) sc->sched.offchannel_duration = 3 * beacon_int / 2; - if (sc->sched.offchannel_duration) { - noa_changed = true; + /* + * If an offchannel switch is scheduled to happen after + * a beacon transmission, update the NoA with one-shot + * values and increment the index. + */ + if (sc->next_chan == &sc->offchannel.chan) { + avp->noa_index++; avp->offchannel_start = tsf_time; - avp->offchannel_duration = - sc->sched.offchannel_duration; + avp->offchannel_duration = sc->sched.offchannel_duration; + + ath_dbg(common, CHAN_CTX, + "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n", + avp->offchannel_duration, + avp->offchannel_start, + avp->noa_index); + + /* + * When multiple contexts are active, the NoA + * has to be recalculated and advertised after + * an offchannel operation. + */ + if (ctx->active && avp->noa_duration) + avp->noa_duration = 0; + + break; } - if (noa_changed) + /* Prevent wrap-around issues */ + if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30)) + avp->noa_duration = 0; + + /* + * If multiple contexts are active, start periodic + * NoA and increment the index for the first + * announcement. + */ + if (ctx->active && + (!avp->noa_duration || sc->sched.force_noa_update)) { avp->noa_index++; + avp->noa_start = tsf_time; + avp->noa_duration = + TU_TO_USEC(cur_conf->beacon_interval) / 2 - + sc->sched.channel_switch_time; - ath_dbg(common, CHAN_CTX, - "periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n", - avp->periodic_noa_duration, - avp->periodic_noa_start, - avp->noa_index); + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) + avp->periodic_noa = false; + else + avp->periodic_noa = true; + + ath_dbg(common, CHAN_CTX, + "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", + avp->noa_duration, + avp->noa_start, + avp->noa_index, + avp->periodic_noa); + } + + if (ctx->active && sc->sched.force_noa_update) + sc->sched.force_noa_update = false; break; case ATH_CHANCTX_EVENT_BEACON_SENT: @@ -736,6 +763,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) sc->offchannel.state = ATH_OFFCHANNEL_IDLE; ieee80211_scan_completed(sc->hw, abort); clear_bit(ATH_OP_SCANNING, &common->op_flags); + spin_lock_bh(&sc->chan_lock); + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + sc->sched.force_noa_update = true; + spin_unlock_bh(&sc->chan_lock); ath_offchannel_next(sc); ath9k_ps_restore(sc); } @@ -1218,10 +1249,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, int noa_len, noa_desc, i = 0; u8 *hdr; - if (!avp->offchannel_duration && !avp->periodic_noa_duration) + if (!avp->offchannel_duration && !avp->noa_duration) return; - noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; + noa_desc = !!avp->offchannel_duration + !!avp->noa_duration; noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; hdr = skb_put(skb, sizeof(noa_ie_hdr)); @@ -1235,13 +1266,17 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, noa->index = avp->noa_index; noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); - if (avp->periodic_noa_duration) { - u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + if (avp->noa_duration) { + if (avp->periodic_noa) { + u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + noa->desc[i].count = 255; + noa->desc[i].interval = cpu_to_le32(interval); + } else { + noa->desc[i].count = 1; + } - noa->desc[i].count = 255; - noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); - noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration); - noa->desc[i].interval = cpu_to_le32(interval); + noa->desc[i].start_time = cpu_to_le32(avp->noa_start); + noa->desc[i].duration = cpu_to_le32(avp->noa_duration); i++; } -- cgit v0.10.2 From 124130d766cefe8e6578695bc33bdc121c8cfaf3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Sep 2014 19:15:58 +0530 Subject: ath9k: Clear offchannel duration properly Clearing the offchannel duration value in the scheduler unconditionally breaks NoA when multiple contexts are active and an offchannel request is deferred, for example, in a scan run. Fix this by clearing the duration only if there is no pending offchannel request. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index ab3d29d..09ff8a6 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1065,7 +1065,10 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) sc->cur_chan = sc->next_chan; sc->cur_chan->stopped = false; sc->next_chan = NULL; - sc->sched.offchannel_duration = 0; + + if (!sc->sched.offchannel_pending) + sc->sched.offchannel_duration = 0; + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) sc->sched.state = ATH_CHANCTX_STATE_IDLE; -- cgit v0.10.2 From 4899827d39ec913d4e46e77f4537945f3e68dca4 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Sep 2014 19:15:59 +0530 Subject: ath9k: Fix channel switch time duration Since the NoA duration is the maximum time the GO interface can be offline, it needs to include the time take to switch channels in the HW. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 09ff8a6..a42fd85 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -419,7 +419,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, avp->noa_index++; avp->noa_start = tsf_time; avp->noa_duration = - TU_TO_USEC(cur_conf->beacon_interval) / 2 - + TU_TO_USEC(cur_conf->beacon_interval) / 2 + sc->sched.channel_switch_time; if (test_bit(ATH_OP_SCANNING, &common->op_flags)) -- cgit v0.10.2 From 167bf96dd87d2a8360cb9e9783006876dac4f579 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 10 Sep 2014 19:16:00 +0530 Subject: ath9k: Fix beacon miss handling The NoA duration for a GO is half the beacon interval and a concurrent context like a STA can be active only for that duration, before switching back to the GO's operating channel. Currently, when multiple beacons are missed, the dwell time for the STA context is extended to improve the chances of receiving a beacon. But the NoA is not updated and this will cause problems since the GO is offline for a period that is longer than the advertised duration. Fix this by ensuring that the NoA is updated first before extending the time slot for the STA context. Also make sure that non-periodic NoA is used for a one-time, longer absence period. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 305db1a..660c151 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -380,6 +380,7 @@ struct ath_chanctx_sched { bool offchannel_pending; bool wait_switch; bool force_noa_update; + bool extend_absence; enum ath_chanctx_state state; u8 beacon_miss; diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index a42fd85..a1b3282 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -371,13 +371,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.switch_start_time = tsf_time; sc->cur_chan->last_beacon = sc->sched.next_tbtt; - /* If at least two consecutive beacons were missed on the STA - * chanctx, stay on the STA channel for one extra beacon period, - * to resync the timer properly. - */ - if (ctx->active && sc->sched.beacon_miss >= 2) - sc->sched.offchannel_duration = 3 * beacon_int / 2; - /* * If an offchannel switch is scheduled to happen after * a beacon transmission, update the NoA with one-shot @@ -405,6 +398,26 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, break; } + + /* + * Clear the extend_absence flag if it had been + * set during the previous beacon transmission, + * since we need to revert to the normal NoA + * schedule. + */ + if (ctx->active && sc->sched.extend_absence) { + avp->noa_duration = 0; + sc->sched.extend_absence = false; + } + + /* If at least two consecutive beacons were missed on the STA + * chanctx, stay on the STA channel for one extra beacon period, + * to resync the timer properly. + */ + if (ctx->active && sc->sched.beacon_miss >= 2) { + avp->noa_duration = 0; + sc->sched.extend_absence = true; + } /* Prevent wrap-around issues */ if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30)) avp->noa_duration = 0; @@ -418,11 +431,17 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, (!avp->noa_duration || sc->sched.force_noa_update)) { avp->noa_index++; avp->noa_start = tsf_time; - avp->noa_duration = - TU_TO_USEC(cur_conf->beacon_interval) / 2 + - sc->sched.channel_switch_time; - if (test_bit(ATH_OP_SCANNING, &common->op_flags)) + if (sc->sched.extend_absence) + avp->noa_duration = (3 * beacon_int / 2) + + sc->sched.channel_switch_time; + else + avp->noa_duration = + TU_TO_USEC(cur_conf->beacon_interval) / 2 + + sc->sched.channel_switch_time; + + if (test_bit(ATH_OP_SCANNING, &common->op_flags) || + sc->sched.extend_absence) avp->periodic_noa = false; else avp->periodic_noa = true; @@ -520,7 +539,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->sched.wait_switch = false; tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; - if (sc->sched.beacon_miss >= 2) { + + if (sc->sched.extend_absence) { sc->sched.beacon_miss = 0; tsf_time *= 3; } -- cgit v0.10.2 From 9a783a139c32a905825ee0aa9597f485ea461f76 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 12 Sep 2014 09:31:52 -0700 Subject: Bluetooth: Fix re-setting RPA as expired when deferring update The hci_update_random_address will clear the RPA_EXPIRED flag and proceed with setting a new one if the flag was set. However, the set_random_addr() function that is called may choose to defer the update to a later moment. In such a case the flag would incorrectly remain unset unless set_random_addr() re-sets it. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0d3782a..067526d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3872,6 +3872,7 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) if (test_bit(HCI_LE_ADV, &hdev->dev_flags) || hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { BT_DBG("Deferring random address update"); + set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags); return; } -- cgit v0.10.2 From a3576ff28e3b6a75d79fdc33c8179e7e2b470e50 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 9 Aug 2014 10:57:59 +0300 Subject: iwlwifi: mvm: add LDPC support Use LDPC for Tx and publish support for Rx in case the chip supports LDPC. Enable it for the 7265 family. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 8e99dff..79c8f74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -220,6 +220,12 @@ static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { {0}, }; +static const struct iwl_ht_params iwl7265_ht_params = { + .stbc = true, + .ldpc = true, + .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), +}; + const struct iwl_cfg iwl3165_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 3165", .fw_name_pre = IWL3165_FW_PRE, @@ -234,7 +240,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -244,7 +250,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, @@ -254,7 +260,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .name = "Intel(R) Wireless N 7265", .fw_name_pre = IWL7265_FW_PRE, IWL_DEVICE_7000, - .ht_params = &iwl7000_ht_params, + .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3d7cc37..07c0f1f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -171,6 +171,7 @@ struct iwl_base_params { /* * @stbc: support Tx STBC and 1*SS Rx STBC + * @ldpc: support Tx/Rx with LDPC * @use_rts_for_aggregation: use rts/cts protection for HT traffic * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40 */ @@ -178,6 +179,7 @@ struct iwl_ht_params { enum ieee80211_smps_mode smps_mode; const bool ht_greenfield_support; /* if used set to true */ const bool stbc; + const bool ldpc; bool use_rts_for_aggregation; u8 ht40_bands; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 07ff7e0..74b796d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -758,6 +758,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; } + if (cfg->ht_params->ldpc) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + if (iwlwifi_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 40718f8..c302e74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -334,6 +334,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + if (cfg->ht_params->ldpc) + vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; + if (num_tx_ants > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 17002cf..6a13120 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -505,10 +505,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, const char *prefix) { - IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n", + IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n", prefix, rs_pretty_lq_type(rate->type), rate->index, rs_pretty_ant(rate->ant), - rate->bw, rate->sgi); + rate->bw, rate->sgi, rate->ldpc); } static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) @@ -742,6 +742,8 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, ucode_rate |= rate->bw; if (rate->sgi) ucode_rate |= RATE_MCS_SGI_MSK; + if (rate->ldpc) + ucode_rate |= RATE_MCS_LDPC_MSK; return ucode_rate; } @@ -779,6 +781,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, /* HT or VHT */ if (ucode_rate & RATE_MCS_SGI_MSK) rate->sgi = true; + if (ucode_rate & RATE_MCS_LDPC_MSK) + rate->ldpc = true; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; @@ -965,13 +969,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->index > IWL_RATE_MCS_9_INDEX); rate->index = rs_ht_to_legacy[rate->index]; + rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ rate->type = is_vht_mimo2(rate) ? LQ_VHT_SISO : LQ_HT_SISO; } - if (num_of_ant(rate->ant) > 1) rate->ant = first_antenna(mvm->fw->valid_tx_ant); @@ -1621,6 +1625,7 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, } rate->bw = rs_bw_from_sta_bw(sta); + rate->ldpc = lq_sta->ldpc; search_tbl->column = col_id; rs_set_expected_tpt_table(lq_sta, search_tbl); @@ -2342,6 +2347,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate->index = i; rate->ant = first_antenna(valid_tx_ant); rate->sgi = false; + rate->ldpc = false; rate->bw = RATE_MCS_CHAN_WIDTH_20; if (band == IEEE80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; @@ -2610,9 +2616,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; lq_sta->is_vht = false; + if (mvm->cfg->ht_params->ldpc && + (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) + lq_sta->ldpc = true; } else { rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); lq_sta->is_vht = true; + + if (mvm->cfg->ht_params->ldpc && + (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) + lq_sta->ldpc = true; } lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, @@ -2622,11 +2635,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, BITS_PER_LONG); - IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", + IWL_DEBUG_RATE(mvm, + "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht); + lq_sta->is_vht, lq_sta->ldpc); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -3032,8 +3046,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_ht20(rate)) ? "20MHz" : (is_ht40(rate)) ? "40MHz" : (is_ht80(rate)) ? "80Mhz" : "BAD BW"); - desc += sprintf(buff+desc, " %s %s\n", + desc += sprintf(buff+desc, " %s %s %s\n", (rate->sgi) ? "SGI" : "NGI", + (rate->ldpc) ? "LDPC" : "BCC", (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f27b9d6..824a750 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -207,6 +207,7 @@ struct rs_rate { u8 ant; u32 bw; bool sgi; + bool ldpc; }; @@ -329,6 +330,7 @@ struct iwl_lq_sta { */ u64 last_tx; bool is_vht; + bool ldpc; /* LDPC Rx is supported by the STA */ enum ieee80211_band band; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; -- cgit v0.10.2 From d4200cb2487042291a056d4364450947344362e1 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Thu, 4 Sep 2014 09:16:49 +0200 Subject: iwlwifi: add and edit 8000 series PCI IDs Edit some 8000 series PCI IDs and add configuration to Dual Band Wireless N 8260 devices. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 23a67bf..3c576ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -117,6 +117,15 @@ static const struct iwl_ht_params iwl8000_ht_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 +const struct iwl_cfg iwl8260_2n_cfg = { + .name = "Intel(R) Dual Band Wireless N 8260", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, +}; + const struct iwl_cfg iwl8260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 8260", .fw_name_pre = IWL8000_FW_PRE, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 07c0f1f..1b9c77d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -343,6 +343,7 @@ extern const struct iwl_cfg iwl3165_2ac_cfg; extern const struct iwl_cfg iwl7265_2ac_cfg; extern const struct iwl_cfg iwl7265_2n_cfg; extern const struct iwl_cfg iwl7265_n_cfg; +extern const struct iwl_cfg iwl8260_2n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index b9d5049..ca68c3c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -405,6 +405,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ -- cgit v0.10.2 From 161bdb7780548918027511f1a2885e9b99d28482 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 27 Jul 2014 08:03:06 +0300 Subject: iwlwifi: mvm: allow preventing dummy notifications The firwmare now allows the driver to disable dummy notifications. These notifications sent by the firmware are an overhead for slow buses. They are still useful for fast buses. Add a hardware switch to prevent these notifications only on devices that work on slow buses. Signed-off-by: Eran Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 3c576ee..c1ef165 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -144,6 +144,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .disable_dummy_notification = true, }; MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 1b9c77d..687e9e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -282,6 +282,7 @@ struct iwl_cfg { bool no_power_up_nic_in_init; const char *default_nvm_file; unsigned int max_rx_agg_size; + bool disable_dummy_notification; }; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f68cba4e0..62c46eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -127,6 +127,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. + * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. */ @@ -137,6 +138,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), + IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), }; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 541b844..b599b52 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1601,6 +1601,8 @@ enum iwl_sf_scenario { #define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ +#define SF_CFG_DUMMY_NOTIF_OFF BIT(16) + /** * Smart Fifo configuration command. * @state: smart fifo state, types listed in enum %iwl_sf_sate. diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index f88410c..7eb78e2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -179,6 +179,10 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, struct ieee80211_sta *sta; int ret = 0; + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && + mvm->cfg->disable_dummy_notification) + sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); + /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. -- cgit v0.10.2 From 099d8086a814689d3c7f58aa6412da6513e1624e Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 28 Aug 2014 02:33:05 +0300 Subject: iwlwifi: enable LDPC in 8000 chip family This chip family supports LDPC so enable it. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index c1ef165..db67631 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -103,6 +103,7 @@ static const struct iwl_base_params iwl8000_base_params = { }; static const struct iwl_ht_params iwl8000_ht_params = { + .ldpc = true, .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), }; -- cgit v0.10.2 From 2536e7c35014c0bd5b8a7b5425004528c208c052 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 31 Aug 2014 02:33:33 +0300 Subject: iwlwifi: mvm: rs: remove max_rate_idx max_rate_idx constraint is deprecated and it's handling is faulty as well as it is relevant only for legacy rates but was considered in HT/VHT. In most cases there was no side effect as max_rate_idx was set to -1 but in certain cases like P2P it got set to an actual rate idx which would limit the maximum rate in HT/VHT by mistake. max_rate_idx should be replaced by the masks fields but for now remove it. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6a13120..94c5299 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2036,18 +2036,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, return; } - /* force user max rate if set by user */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < index)) { - index = lq_sta->max_rate_idx; - update_lq = 1; - window = &(tbl->win[index]); - IWL_DEBUG_RATE(mvm, - "Forcing user max rate %d\n", - index); - goto lq_update; - } - + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ window = &(tbl->win[index]); /* @@ -2135,10 +2124,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, low = high_low & 0xff; high = (high_low >> 8) & 0xff; - /* If user set max rate, dont allow higher than user constrain */ - if ((lq_sta->max_rate_idx != -1) && - (lq_sta->max_rate_idx < high)) - high = IWL_RATE_INVALID; + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ sr = window->success_ratio; @@ -2370,23 +2356,13 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct ieee80211_tx_rate_control *txrc) { struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; struct iwl_op_mode *op_mode __maybe_unused = (struct iwl_op_mode *)mvm_r; struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; - /* Get max rate if user set max rate */ - if (lq_sta) { - lq_sta->max_rate_idx = txrc->max_rate_idx; - if ((sband->band == IEEE80211_BAND_5GHZ) && - (lq_sta->max_rate_idx != -1)) - lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; - if ((lq_sta->max_rate_idx < 0) || - (lq_sta->max_rate_idx >= IWL_RATE_COUNT)) - lq_sta->max_rate_idx = -1; - } + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ /* Treat uninitialized rate scaling data same as non-existing. */ if (lq_sta && !lq_sta->pers.drv) { @@ -2587,7 +2563,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; lq_sta->band = sband->band; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 824a750..98bb9b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -345,7 +345,6 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; - s8 max_rate_idx; /* Max rate set by user */ u8 missed_rate_counter; struct iwl_lq_cmd lq; -- cgit v0.10.2 From bc44886d2645bb4c0422db09f67661638eacc3d1 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 20 Aug 2014 11:49:11 +0300 Subject: iwlwifi: mvm: reset ucode_loaded flag when mac80211 stop is called We rely on the value of the mvm->ucode_loaded flag to decide whether or not we can perform certain operations (e.g. access to some debugfs entries), so we need to reset it when the mac80211 stop operation is called and the hardware is shutdown. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 069bb8e..bcfb03c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -890,6 +890,8 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); + mvm->ucode_loaded = false; + mutex_unlock(&mvm->mutex); /* -- cgit v0.10.2 From a26d4e7b096d85eeea0ce08950744e2887cb46fa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 20 Aug 2014 10:21:07 +0300 Subject: iwlwifi: mvm: fail temp test enabling if the ucode is not loaded If the ucode is not loaded, don't allow the temperature test to be started, but allow it to be changed or stopped if already running. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index d98ee10..85eb847 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -288,6 +288,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, { int temperature; + if (!mvm->ucode_loaded && !mvm->temperature_test) + return -EIO; + if (kstrtoint(buf, 10, &temperature)) return -EINVAL; /* not a legal temperature */ -- cgit v0.10.2 From f3bd58f486acd954ca8d90f8733d752dbd98eec6 Mon Sep 17 00:00:00 2001 From: Max Stepanov Date: Mon, 4 Aug 2014 13:55:01 +0300 Subject: iwlwifi: mvm: add MVM_FW_MCAST_FILTER_PASS_ALL option Add MVM_FW_MCAST_FILTER_PASS_ALL option to iwl-dbg-cfg.ini configuration file to enable/disable FW multicast filtering. Signed-off-by: Max Stepanov Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index dd00e8f..cb48656 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -86,5 +86,6 @@ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 +#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index bcfb03c..089d7b3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1200,14 +1200,15 @@ static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mcast_filter_cmd *cmd; struct netdev_hw_addr *addr; - int addr_count = netdev_hw_addr_list_count(mc_list); - bool pass_all = false; + int addr_count; + bool pass_all; int len; - if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) { - pass_all = true; + addr_count = netdev_hw_addr_list_count(mc_list); + pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES || + IWL_MVM_FW_MCAST_FILTER_PASS_ALL; + if (pass_all) addr_count = 0; - } len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4); cmd = kzalloc(len, GFP_ATOMIC); -- cgit v0.10.2 From f58220f6b9ba69c782eafbfe703be8c4bca6b33d Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sat, 16 Aug 2014 01:30:30 +0300 Subject: iwlwifi: mvm: rs: don't zero tx stats after idle Move the tx stats to the persistent area of lq_sta to avoid them being zeroed out every time rs reinitializes which happens after tx idle for 5 secs for example. The automatic zeroing out made them difficult to use. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 94c5299..f77dfe4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -672,8 +672,10 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, return -EINVAL; if (tbl->column != RS_COLUMN_INVALID) { - lq_sta->tx_stats[tbl->column][scale_index].total += attempts; - lq_sta->tx_stats[tbl->column][scale_index].success += successes; + struct lq_sta_pers *pers = &lq_sta->pers; + + pers->tx_stats[tbl->column][scale_index].total += attempts; + pers->tx_stats[tbl->column][scale_index].success += successes; } /* Select window for current tx bit rate */ @@ -3171,7 +3173,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_read(struct file *file, "%s,", column_name[col]); for (rate = 0; rate < IWL_RATE_COUNT; rate++) { - stats = &(lq_sta->tx_stats[col][rate]); + stats = &(lq_sta->pers.tx_stats[col][rate]); pos += scnprintf(pos, endpos - pos, "%llu/%llu,", stats->success, @@ -3190,7 +3192,7 @@ static ssize_t rs_sta_dbgfs_drv_tx_stats_write(struct file *file, size_t count, loff_t *ppos) { struct iwl_lq_sta *lq_sta = file->private_data; - memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats)); + memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats)); return count; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 98bb9b7..95c4b96 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -333,8 +333,6 @@ struct iwl_lq_sta { bool ldpc; /* LDPC Rx is supported by the STA */ enum ieee80211_band band; - struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ unsigned long active_legacy_rate; unsigned long active_siso_rate; @@ -362,11 +360,14 @@ struct iwl_lq_sta { int tpc_reduce; /* persistent fields - initialized only once - keep last! */ - struct { + struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS u32 dbg_fixed_rate; u8 dbg_fixed_txp_reduction; #endif + u8 chains; + s8 chain_signal[IEEE80211_MAX_CHAINS]; + struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; }; -- cgit v0.10.2 From f7f89e7baef643788f09d9629012ea1612d827bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Aug 2014 15:24:44 +0200 Subject: iwlwifi: mvm: disable aggregation queues in station DB in FW When disabling aggregation, disable the queues in the station DB in the firmware, otherwise we leave the tfd_queue_mask in a wrong state after an aggregation session has been torn down. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index dd9f3a4..666f16b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -948,8 +948,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } tid_data->ssn = 0xffff; + tid_data->state = IWL_AGG_OFF; + mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE; + spin_unlock_bh(&mvmsta->lock); + + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, txq_id, true); - /* fall through */ + return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: /* @@ -1003,6 +1011,8 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true); } -- cgit v0.10.2 From 3a736bcb18f797996064cf18f4eecc4b3e46d39a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 10 Sep 2014 11:16:41 +0300 Subject: iwlwifi: trans: don't configure the set_active in SCD for dvm This configuration is not needed for dvm, and it actually broke it. Reported-by: Oliver Hartkopp Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index c89985a..eb31648 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -377,6 +377,7 @@ enum iwl_trans_status { * if unset 4k will be the RX buffer size * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @queue_watchdog_timeout: time (in ms) after which queues * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries @@ -392,6 +393,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; unsigned int queue_watchdog_timeout; const char *const *command_names; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 87f278c..5d8c562 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -460,6 +460,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; + trans_cfg.scd_set_active = true; snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index a4fedc4..1aea6b6 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -257,6 +257,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @cmd_queue - command queue number * @rx_buf_size_8k: 8 kB RX buffer size * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) + * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access @@ -306,6 +307,7 @@ struct iwl_trans_pcie { bool rx_buf_size_8k; bool bc_table_dword; + bool scd_set_active; u32 rx_page_order; const char *const *command_names; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3076e0e..4add964 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1171,6 +1171,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; + trans_pcie->scd_set_active = trans_cfg->scd_set_active; /* Initialize NAPI here - it should be before registering to mac80211 * in the opmode but after the HW struct is allocated. diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index a6336b4..35fe38e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1080,7 +1080,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, fifo = cfg->fifo; /* Disable the scheduler prior configuring the cmd queue */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, 0); /* Stop this Tx queue before configuring it */ @@ -1142,7 +1143,8 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, SCD_QUEUE_STTS_REG_MSK); /* enable the scheduler for this queue (only) */ - if (txq_id == trans_pcie->cmd_queue) + if (txq_id == trans_pcie->cmd_queue && + trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, BIT(txq_id)); } -- cgit v0.10.2 From c2a2b28bb7fbcb8e0e11b84714992750bba7b699 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 7 Sep 2014 11:41:05 +0300 Subject: iwlwifi: make hw rev checking more readable Rather than ANDing with a mask - use existing macros, which are more readable. Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 23d059a..3f6f015 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -295,6 +295,16 @@ #define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) + +/** + * hw_rev values + */ +enum { + SILICON_A_STEP = 0, + SILICON_B_STEP, +}; + + #define CSR_HW_REV_TYPE_MSK (0x000FFF0) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5eef4ae..7a2cbf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -193,7 +193,7 @@ void iwl_force_nmi(struct iwl_trans *trans) * DEVICE_SET_NMI_8000B_REG - is used. */ if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - ((trans->hw_rev & 0xc) == 0x0)) + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); else iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 4fafd4b..af07456 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -64,6 +64,7 @@ *****************************************************************************/ #include #include "iwl-trans.h" +#include "iwl-csr.h" #include "mvm.h" #include "iwl-eeprom-parse.h" #include "iwl-eeprom-read.h" @@ -349,7 +350,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) /* Maximal size depends on HW family and step */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) max_section_size = IWL_MAX_NVM_SECTION_SIZE; - else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */ + else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; else /* Family 8000 B-step */ max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 4add964..ae99240 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2190,7 +2190,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) trans->hw_rev = (trans->hw_rev & 0xfff0) | - ((trans->hw_rev << 2) & 0xc); + (CSR_HW_REV_STEP(trans->hw_rev << 2)); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), -- cgit v0.10.2 From 5d4185ae0c68eeff26d0390a4e99b6e7359a8b83 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Sep 2014 21:16:06 +0200 Subject: iwlwifi: pcie: clear command data on freeing When freeing the structures used for command data, clear their memory as they may have contained key material at some point. Also clear the duplicated buffer when freeing it to be safe; currently key material is never put there but that may change. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 702f47f..7b7e2f2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -640,7 +640,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); if (reclaim) { - kfree(txq->entries[cmd_index].free_buf); + kzfree(txq->entries[cmd_index].free_buf); txq->entries[cmd_index].free_buf = NULL; } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 35fe38e..eb8e298 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -620,8 +620,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id) /* De-alloc array of command/tx buffers */ if (txq_id == trans_pcie->cmd_queue) for (i = 0; i < txq->q.n_window; i++) { - kfree(txq->entries[i].cmd); - kfree(txq->entries[i].free_buf); + kzfree(txq->entries[i].cmd); + kzfree(txq->entries[i].free_buf); } /* De-alloc circular buffer of TFDs */ @@ -1409,7 +1409,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_meta->flags = cmd->flags; if (WARN_ON_ONCE(txq->entries[idx].free_buf)) - kfree(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); -- cgit v0.10.2 From bbab758279a14556e6ccb17b1f98935634eeb8d5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 10 Sep 2014 11:00:16 +0300 Subject: iwlwifi: define the non shared antenna per hardware The sharing model will differ in new hardware. Define the non shared antenna based on the device so that different devices can have different names for the non shared antenna. Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 79c8f74..b04b885 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -131,7 +131,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl7000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ + .non_shared_ant = ANT_A const struct iwl_cfg iwl7260_2ac_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index db67631..4ae8ba6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -116,7 +116,8 @@ static const struct iwl_ht_params iwl8000_ht_params = { .max_data_size = IWL60_RTC_DATA_SIZE, \ .base_params = &iwl8000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000 + .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ + .non_shared_ant = ANT_A const struct iwl_cfg iwl8260_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 8260", diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 687e9e1..2ef83a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -230,6 +230,7 @@ struct iwl_pwr_tx_backoff { * @max_data_size: The maximal length of the fw data section * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna + * @non_shared_ant: the antenna that is for WiFi only * @nvm_ver: NVM version * @nvm_calib_ver: NVM calibration version * @lib: pointer to the lib ops @@ -262,6 +263,7 @@ struct iwl_cfg { const u32 max_inst_size; u8 valid_tx_ant; u8 valid_rx_ant; + u8 non_shared_ant; bool bt_shared_single_ant; u16 nvm_ver; u16 nvm_calib_ver; diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 6e8f3e2..8df2021 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1146,6 +1146,10 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { + /* there is no other antenna, shared antenna is always available */ + if (mvm->cfg->bt_shared_single_ant) + return true; + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index ed09194..c67296e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -213,7 +213,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, if (info->band == IEEE80211_BAND_2GHZ && !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) - rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS; + rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS; else rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; -- cgit v0.10.2 From b2b7875bfb6c69bb708b61c5f745491d240161a1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Sep 2014 16:42:54 +0200 Subject: iwlwifi: mvm: don't update quota in firmware too often When updating quota in the firmware, it has to reset quite a bit of internal state, which apparently can have an adverse impact on its operation. Avoid that by only updating the quota command when there are any signification changes, i.e. added/removed bindings or changes in quota that are bigger than 8 TU within a binding. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index cb48656..1181089 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -87,5 +87,6 @@ #define IWL_MVM_BT_COEX_CORUNNING 1 #define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 +#define IWL_MVM_QUOTA_THRESHOLD 8 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 21d60602..23fd711 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -454,6 +454,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_MVM_STATION_COUNT; i++) RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); + /* reset quota debouncing buffer - 0xff will yield invalid data */ + memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); + /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); if (ret) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e292de9..f05b7d7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -709,6 +709,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + struct iwl_time_quota_cmd last_quota_cmd; + #ifdef CONFIG_NL80211_TESTMODE u32 noa_duration; struct ieee80211_vif *noa_vif; diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 5fd502d..1eab2f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -175,12 +175,14 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif) { struct iwl_time_quota_cmd cmd = {}; - int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat; + int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat; struct iwl_mvm_quota_iterator_data data = { .n_interfaces = {}, .colors = { -1, -1, -1, -1 }, .disabled_vif = disabled_vif, }; + struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd; + bool send = false; lockdep_assert_held(&mvm->mutex); @@ -293,15 +295,34 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, /* check that we have non-zero quota for all valid bindings */ for (i = 0; i < MAX_BINDINGS; i++) { + if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color) + send = true; + if (cmd.quotas[i].max_duration != last->quotas[i].max_duration) + send = true; + if (abs((int)le32_to_cpu(cmd.quotas[i].quota) - + (int)le32_to_cpu(last->quotas[i].quota)) + > IWL_MVM_QUOTA_THRESHOLD) + send = true; if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID)) continue; WARN_ONCE(cmd.quotas[i].quota == 0, "zero quota on binding %d\n", i); } - ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - return ret; + if (send) { + err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, + sizeof(cmd), &cmd); + } else { + /* don't send a practically unchanged command, the firmware has + * to re-initialize a lot of state and that can have an adverse + * impact on it + */ + err = 0; + } + + if (err) + IWL_ERR(mvm, "Failed to send quota: %d\n", err); + else + mvm->last_quota_cmd = cmd; + return err; } -- cgit v0.10.2 From ad25c1ee55b1e125d71891496eb52ccb508dd3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toralf=20F=C3=B6rster?= Date: Tue, 9 Sep 2014 20:08:53 +0200 Subject: iwlwifi/iwl-drv.c: fix typo defualt -> default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit trivial, but this is user visible b/c it is in the help text Signed-off-by: Toralf Förster Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index aefd94c..ed673ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1363,7 +1363,7 @@ MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)") module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (defualt: 0 dB)"); + "specify antenna coupling in dB (default: 0 dB)"); module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, -- cgit v0.10.2 From 6d93affd3a49a7f846bb632ff0d19c02ac2a7bf0 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Tue, 26 Aug 2014 07:09:52 +0300 Subject: iwlwifi: mvm: remove unused static inline function Signed-off-by: Avri Altman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index eb31648..9eb8524 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -828,12 +828,6 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); } -static inline void -iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn) -{ - iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL); -} - static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, u32 txq_bm) { -- cgit v0.10.2 From 34e611ea2a9d88ccf77b2a073ab9b0c53e58e6f8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Sep 2014 10:28:01 +0200 Subject: iwlwifi: mvm: update d0i3 debugfs A lot of the newer d0i3 ref additions weren't added to the debugfs file, fix that and add a comment to remember to do it in the future. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 85eb847..95eb9a5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1259,6 +1259,18 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); PRINT_MVM_REF(IWL_MVM_REF_USER); + PRINT_MVM_REF(IWL_MVM_REF_TX); + PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); + PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); + PRINT_MVM_REF(IWL_MVM_REF_START_AP); + PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); + PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); + PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); + PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); + PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); + PRINT_MVM_REF(IWL_MVM_REF_NMI); + PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index f05b7d7..4b1db9a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -274,6 +274,8 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, + /* update debugfs.c when changing this */ + IWL_MVM_REF_COUNT, }; -- cgit v0.10.2 From a0a09243e02e0ad6a366139093d80b870ec9a16e Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 4 Sep 2014 12:29:15 +0300 Subject: iwlwifi: mvm: use the firmware to get the temperature during CT kill Reading the temperature directly from the hardware, without the help of the firmware, is a complex process and is not entirely the same for different hardware. Also, some NICs don't easily allow access to the sensors when the firmware is not running, which would add even more complexity to the code. To reduce the code complexity and to avoid code duplication between the firmware and the driver, boot the firmware briefly to read the current temperature while in CT kill mode. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index b599b52..fbcc036 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -205,6 +205,10 @@ enum { REPLY_SF_CFG_CMD = 0xd1, REPLY_BEACON_FILTERING_CMD = 0xd2, + /* DTS measurements */ + CMD_DTS_MEASUREMENT_TRIGGER = 0xdc, + DTS_MEASUREMENT_NOTIFICATION = 0xdd, + REPLY_DEBUG_CMD = 0xf0, DEBUG_LOG_MSG = 0xf7, @@ -1618,4 +1622,32 @@ struct iwl_sf_cfg_cmd { __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; } __packed; /* SF_CFG_API_S_VER_2 */ +/* DTS measurements */ + +enum iwl_dts_measurement_flags { + DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), + DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), +}; + +/** + * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements + * + * @flags: indicates which measurements we want as specified in &enum + * iwl_dts_measurement_flags + */ +struct iwl_dts_measurement_cmd { + __le32 flags; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ + +/** + * iwl_dts_measurement_notif - notification received with the measurements + * + * @temp: the measured temperature + * @voltage: the measured voltage + */ +struct iwl_dts_measurement_notif { + __le32 temp; + __le32 voltage; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 089d7b3..5c33d2d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -815,12 +815,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->rx_ba_sessions = 0; } -static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +int __iwl_mvm_mac_start(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* Clean up some internal and mac80211 state on restart */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) @@ -837,6 +836,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) iwl_mvm_d0i3_enable_tx(mvm, NULL); } + return ret; +} + +static int iwl_mvm_mac_start(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = __iwl_mvm_mac_start(mvm); mutex_unlock(&mvm->mutex); return ret; @@ -862,14 +871,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw) mutex_unlock(&mvm->mutex); } -static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - - flush_work(&mvm->d0i3_exit_work); - flush_work(&mvm->async_handlers_wk); - - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); /* disallow low power states when the FW is down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -891,7 +895,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) iwl_mvm_del_aux_sta(mvm); mvm->ucode_loaded = false; +} +static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + flush_work(&mvm->d0i3_exit_work); + flush_work(&mvm->async_handlers_wk); + + mutex_lock(&mvm->mutex); + __iwl_mvm_mac_stop(mvm); mutex_unlock(&mvm->mutex); /* diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4b1db9a..a36fa6c6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -792,6 +792,9 @@ struct iwl_rate_info { u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ }; +void __iwl_mvm_mac_stop(struct iwl_mvm *mvm); +int __iwl_mvm_mac_start(struct iwl_mvm *mvm); + /****************** * MVM Methods ******************/ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 5d8c562..9710084 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BCAST_FILTER_CMD), CMD(REPLY_SF_CFG_CMD), CMD(REPLY_BEACON_FILTERING_CMD), + CMD(CMD_DTS_MEASUREMENT_TRIGGER), + CMD(DTS_MEASUREMENT_NOTIFICATION), CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(MAC_PM_POWER_TABLE), CMD(BT_COEX_CI), diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index c3e1fe4..c750ca7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -69,275 +69,99 @@ #include "iwl-csr.h" #include "iwl-prph.h" -#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ -/* VBG - Voltage Band Gap error data (temperature offset) */ -#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2) -#define MEAS_VBG_MIN_VAL 2300 -#define MEAS_VBG_MAX_VAL 3000 -#define MEAS_VBG_DEFAULT_VAL 2700 -#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE) -#define MIN_TEMPERATURE 0 -#define MAX_TEMPERATURE 125 -#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1) -#define PTAT_DIGITAL_VALUE_MIN_VALUE 0 -#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF -#define DTS_VREFS_NUM 5 -static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags) -{ - return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> - DTS_DIODE_REG_FLAGS_VREFS_ID_POS; -} +#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ -#define CALC_VREFS_MIN_DIFF 43 -#define CALC_VREFS_MAX_DIFF 51 -#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF) -#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF -#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23 - -/* - * @digital_value: The diode's digital-value sampled (temperature/voltage) - * @vref_low: The lower voltage-reference (the vref just below the diode's - * sampled digital-value) - * @vref_high: The higher voltage-reference (the vref just above the diode's - * sampled digital-value) - * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref) - * bits[6:2]: Reserved. - * bits[7:7]: Indicates completion of at least 1 successful sample - * since last DTS reset. - */ -struct iwl_mvm_dts_diode_bits { - u8 digital_value; - u8 vref_low; - u8 vref_high; - u8 flags; -} __packed; - -union dts_diode_results { - u32 reg_value; - struct iwl_mvm_dts_diode_bits bits; -} __packed; - -static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) +static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { - struct iwl_nvm_section calib_sec; - const __le16 *calib; - u16 vbg; - - /* TODO: move parsing to NVM code */ - calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; - calib = (__le16 *)calib_sec.data; + u32 duration = mvm->thermal_throttle.params->ct_kill_duration; - vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); + if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) - vbg = MEAS_VBG_DEFAULT_VAL; + IWL_ERR(mvm, "Enter CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, true); - return vbg; + /* Don't schedule an exit work if we're in test mode, since + * the temperature will not change unless we manually set it + * again (or disable testing). + */ + if (!mvm->temperature_test) + schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, + round_jiffies_relative(duration * HZ)); } -static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) +static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) { - const u8 *calib; - u8 ptat, pa1, pa2, median; - - /* TODO: move parsing to NVM code */ - calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; - ptat = calib[OTP_DTS_DIODE_DEVIATION * 2]; - pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1]; - pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2]; - - /* get the median: */ - if (ptat > pa1) { - if (ptat > pa2) - median = (pa1 > pa2) ? pa1 : pa2; - else - median = ptat; - } else { - if (pa1 > pa2) - median = (ptat > pa2) ? ptat : pa2; - else - median = pa1; - } + if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) + return; - return ptat - median; + IWL_ERR(mvm, "Exit CT Kill\n"); + iwl_mvm_set_hw_ctkill_state(mvm, false); } -static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) +static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) { - /* Calibrate the PTAT digital value, based on PTAT deviation data: */ - s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); + struct iwl_mvm *mvm = + container_of(notif_wait, struct iwl_mvm, notif_wait); + int *temp = data; + struct iwl_dts_measurement_notif *notif; + int len = iwl_rx_packet_payload_len(pkt); + + if (WARN_ON_ONCE(len != sizeof(*notif))) { + IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); + return true; + } - if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) - new_val = PTAT_DIGITAL_VALUE_MAX_VALUE; - else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE) - new_val = PTAT_DIGITAL_VALUE_MIN_VALUE; + notif = (void *)pkt->data; - return new_val; -} + *temp = le32_to_cpu(notif->temp); -static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u8 vrefs_results[DTS_VREFS_NUM]; - u8 low_vref_index = 0, flags; - u32 reg; - - reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG); - memcpy(vrefs_results, ®, sizeof(reg)); - reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG); - vrefs_results[4] = reg & 0xff; - - if (avg_ptat->bits.digital_value < vrefs_results[0] || - avg_ptat->bits.digital_value > vrefs_results[4]) - return false; - - if (avg_ptat->bits.digital_value > vrefs_results[3]) - low_vref_index = 3; - else if (avg_ptat->bits.digital_value > vrefs_results[2]) - low_vref_index = 2; - else if (avg_ptat->bits.digital_value > vrefs_results[1]) - low_vref_index = 1; - - avg_ptat->bits.vref_low = vrefs_results[low_vref_index]; - avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1]; - flags = avg_ptat->bits.flags; - avg_ptat->bits.flags = - (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) | - (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID); - return true; -} + /* shouldn't be negative, but since it's s32, make sure it isn't */ + if (WARN_ON_ONCE(*temp < 0)) + *temp = 0; -/* - * return true it the results are valid, and false otherwise. - */ -static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, - union dts_diode_results *avg_ptat) -{ - u32 reg; - u8 tmp; - - /* fill the diode value and pass_once with avg-reg results */ - reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG); - reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE; - avg_ptat->reg_value = reg; - - /* calibrate the PTAT digital value */ - tmp = avg_ptat->bits.digital_value; - tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp); - avg_ptat->bits.digital_value = tmp; - - /* - * fill vrefs fields, based on the avgVrefs results - * and the diode value - */ - return dts_get_adjacent_vrefs(mvm, avg_ptat) && - DTS_DIODE_VALID(avg_ptat->bits.flags); + IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp); + return true; } -static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, - u16 volt_band_gap) +static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { - u32 tmp_result; - u8 vrefs_diff; - /* - * For temperature calculation (at the end, shift right by 23) - * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) } - * (D2-D1) == 43 44 45 46 47 48 49 50 51 - */ - static const u16 calc_lut[CALC_LUT_SIZE] = { - 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, + struct iwl_dts_measurement_cmd cmd = { + .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; - /* - * The diff between the high and low voltage-references is assumed - * to be strictly be in range of [60,68] - */ - vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; - - if (vrefs_diff < CALC_VREFS_MIN_DIFF || - vrefs_diff > CALC_VREFS_MAX_DIFF) - return TEMPERATURE_ERROR; - - /* calculate the result: */ - tmp_result = - vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9); - tmp_result += avg_ptat.bits.digital_value; - tmp_result -= avg_ptat.bits.vref_high; - - /* multiply by the LUT value (based on the diff) */ - tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; - - /* - * Get the BandGap (the voltage refereces source) error data - * (temperature offset) - */ - tmp_result *= volt_band_gap; - - /* - * here, tmp_result value can be up to 32-bits. We want to right-shift - * it *without* sign-extend. - */ - tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; - - /* - * at this point, tmp_result should be in the range: - * 200 <= tmp_result <= 365 - */ - return (s16)tmp_result - 240; -} - -static s32 check_nic_temperature(struct iwl_mvm *mvm) -{ - u16 volt_band_gap; - union dts_diode_results avg_ptat; - - volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - /* SV initialization */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1); - iwl_write_prph(mvm->trans, DTSC_CFG_MODE, - DTSC_CFG_MODE_PERIODIC); - - /* wait for results */ - msleep(100); - if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) - return TEMPERATURE_ERROR; - - /* disable DTS */ - iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); - - return calculate_nic_temperature(avg_ptat, volt_band_gap); + return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, + sizeof(cmd), &cmd); } -static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) +static int iwl_mvm_get_temp(struct iwl_mvm *mvm) { - u32 duration = mvm->thermal_throttle.params->ct_kill_duration; + struct iwl_notification_wait wait_temp_notif; + static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; + int ret, temp; - if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + lockdep_assert_held(&mvm->mutex); - IWL_ERR(mvm, "Enter CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, true); + iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, + temp_notif, ARRAY_SIZE(temp_notif), + iwl_mvm_temp_notif, &temp); - /* Don't schedule an exit work if we're in test mode, since - * the temperature will not change unless we manually set it - * again (or disable testing). - */ - if (!mvm->temperature_test) - schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, - round_jiffies_relative(duration * HZ)); -} + ret = iwl_mvm_get_temp_cmd(mvm); + if (ret) { + IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret); + iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); + return ret; + } -static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) -{ - if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return; + ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, + IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); + if (ret) { + IWL_ERR(mvm, "Getting the temperature timed out\n"); + return ret; + } - IWL_ERR(mvm, "Exit CT Kill\n"); - iwl_mvm_set_hw_ctkill_state(mvm, false); + return temp; } static void check_exit_ctkill(struct work_struct *work) @@ -352,28 +176,36 @@ static void check_exit_ctkill(struct work_struct *work) duration = tt->params->ct_kill_duration; + mutex_lock(&mvm->mutex); + + if (__iwl_mvm_mac_start(mvm)) + goto reschedule; + /* make sure the device is available for direct read/writes */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) { + __iwl_mvm_mac_stop(mvm); goto reschedule; + } - iwl_trans_start_hw(mvm->trans); - temp = check_nic_temperature(mvm); - iwl_trans_stop_device(mvm->trans); + temp = iwl_mvm_get_temp(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); - if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { - IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); + __iwl_mvm_mac_stop(mvm); + + if (temp < 0) goto reschedule; - } + IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); if (temp <= tt->params->ct_kill_exit) { + mutex_unlock(&mvm->mutex); iwl_mvm_exit_ctkill(mvm); return; } reschedule: + mutex_unlock(&mvm->mutex); schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, round_jiffies(duration * HZ)); } -- cgit v0.10.2 From 4bfa47f3174155d4da088c5259e5fe2fcac01cf4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 11 Sep 2014 16:19:43 +0300 Subject: iwlwifi: mvm: allow to collect debug data when restart is disabled In some testing configuration, the firmware restart flow is not enabled. Allow to collect logs even in this case. Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5c33d2d..e4d62f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -670,8 +670,9 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, } #ifdef CONFIG_IWLWIFI_DEBUGFS -static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { + static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; @@ -763,20 +764,16 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); mvm->fw_error_dump = fw_error_dump; + + /* notify the userspace about the error we had */ + kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); } #endif static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; - iwl_mvm_fw_error_dump(mvm); - /* notify the userspace about the error we had */ - kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); -#endif - iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; @@ -903,6 +900,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) flush_work(&mvm->d0i3_exit_work); flush_work(&mvm->async_handlers_wk); + flush_work(&mvm->fw_error_dump_wk); mutex_lock(&mvm->mutex); __iwl_mvm_mac_stop(mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index a36fa6c6..1fdebb8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -651,6 +651,7 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; + struct work_struct fw_error_dump_wk; struct iwl_mvm_dump_ptrs *fw_error_dump; #ifdef CONFIG_IWLWIFI_LEDS @@ -1162,5 +1163,10 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +#else +static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {} +#endif #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 9710084..f887779 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -366,6 +366,8 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) return 0; } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -433,6 +435,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); + INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); @@ -784,6 +787,16 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) module_put(THIS_MODULE); } +static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) +{ + struct iwl_mvm *mvm = + container_of(work, struct iwl_mvm, fw_error_dump_wk); + + mutex_lock(&mvm->mutex); + iwl_mvm_fw_error_dump(mvm); + mutex_unlock(&mvm->mutex); +} + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -849,6 +862,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); + } else if (fw_error) { + schedule_work(&mvm->fw_error_dump_wk); } } -- cgit v0.10.2 From 3d4060d58130aa805fb505c8ed4a9fbf8a3e09be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Sep 2014 14:12:06 +0200 Subject: iwlwifi: mvm: fix quota update avoidance When not updating the quota, the new command shouldn't be stored as otherwise slowly drifting quota would never update the firmware. Fix this by storing the command only when it was also sent. Since the error message also only makes sense when attempting to send the command, just short-circuit the function when there's no need to send the command. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 1eab2f2..dbb2594 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -309,17 +309,16 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, "zero quota on binding %d\n", i); } - if (send) { - err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, - sizeof(cmd), &cmd); - } else { + if (!send) { /* don't send a practically unchanged command, the firmware has * to re-initialize a lot of state and that can have an adverse * impact on it */ - err = 0; + return 0; } + err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); + if (err) IWL_ERR(mvm, "Failed to send quota: %d\n", err); else -- cgit v0.10.2 From 397453377642e266676d60cb174ef58f3e202c70 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 10 Sep 2014 16:40:41 +0300 Subject: iwlwifi: mvm: reduce active dwell time Reduce basic active dwell time from 30 ms on 2.4 GHz and 20 on 5.2 to 20 on 2.4 and 10 on 5.2. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index bf9c63d..09545f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -160,8 +160,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid, static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) { if (band == IEEE80211_BAND_2GHZ) - return 30 + 3 * (n_ssids + 1); - return 20 + 2 * (n_ssids + 1); + return 20 + 3 * (n_ssids + 1); + return 10 + 2 * (n_ssids + 1); } static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band) -- cgit v0.10.2 From f7d8b70290e64eefcacfa598e46638689b8b6d11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Sep 2014 15:49:19 +0200 Subject: iwlwifi: mvm: update QoS parameters when they change The QoS parameters can change during the lifetime of the BSS, and more importantly hostapd only sets up the correct ones after having started the AP/GO. Resend the MAC context when the parameters change, with the updated parameters. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e4d62f2..56901f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1739,7 +1739,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, return; if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | - BSS_CHANGED_BANDWIDTH) && + BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) && iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL)) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); -- cgit v0.10.2 From d4317252330d9d0b24a8d707270c38cf3c0943ad Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 7 Sep 2014 19:18:31 +0300 Subject: iwlwifi: mvm: move TDLS code to separate file The upcoming TDLS channel-switch functionality is big enough to warrant a separate file. Move existing related functions to the new file. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index a282359..2d7c3ea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o iwlmvm-y += power.o coex.o coex_legacy.o -iwlmvm-y += tt.o offloading.o +iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 56901f8..a3bb4a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1420,28 +1420,6 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm, } #endif -static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - mvmsta = iwl_mvm_sta_from_mac80211(sta); - ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, - NL80211_TDLS_TEARDOWN, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, - GFP_KERNEL); - } -} - static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1970,48 +1948,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } -int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - int count = 0; - int i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], - lockdep_is_held(&mvm->mutex)); - if (!sta || IS_ERR(sta) || !sta->tdls) - continue; - - if (vif) { - mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (mvmsta->vif != vif) - continue; - } - - count++; - } - - return count; -} - -static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - bool sta_added) -{ - int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); - - /* - * Disable ps when the first TDLS sta is added and re-enable it - * when the last TDLS sta is removed - */ - if ((tdls_sta_cnt == 1 && sta_added) || - (tdls_sta_cnt == 0 && !sta_added)) - iwl_mvm_power_update_mac(mvm); -} - static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2185,27 +2121,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX); } -static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; - - /* - * iwl_mvm_protect_session() reads directly from the device - * (the system time), so make sure it is available. - */ - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) - return; - - mutex_lock(&mvm->mutex); - /* Protect the session to hear the TDLS setup response on the channel */ - iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); - mutex_unlock(&mvm->mutex); - - iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); -} - static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 1fdebb8..6eb1f85 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1161,6 +1161,11 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* TDLS */ int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm); +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added); +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); #ifdef CONFIG_IWLWIFI_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c new file mode 100644 index 0000000..66c82df --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * 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) 2014 Intel Mobile Communications 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2014 Intel Mobile Communications 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 "mvm.h" +#include "time-event.h" + +void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + ieee80211_tdls_oper_request(mvmsta->vif, sta->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, + GFP_KERNEL); + } +} + +int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct ieee80211_sta *sta; + struct iwl_mvm_sta *mvmsta; + int count = 0; + int i; + + lockdep_assert_held(&mvm->mutex); + + for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (!sta || IS_ERR(sta) || !sta->tdls) + continue; + + if (vif) { + mvmsta = iwl_mvm_sta_from_mac80211(sta); + if (mvmsta->vif != vif) + continue; + } + + count++; + } + + return count; +} + +void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool sta_added) +{ + int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif); + + /* + * Disable ps when the first TDLS sta is added and re-enable it + * when the last TDLS sta is removed + */ + if ((tdls_sta_cnt == 1 && sta_added) || + (tdls_sta_cnt == 0 && !sta_added)) + iwl_mvm_power_update_mac(mvm); +} + +void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; + + /* + * iwl_mvm_protect_session() reads directly from the device + * (the system time), so make sure it is available. + */ + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS)) + return; + + mutex_lock(&mvm->mutex); + /* Protect the session to hear the TDLS setup response on the channel */ + iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); + mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS); +} -- cgit v0.10.2 From 49c6d8021f11a4e86ab2689c62fbfca2ea8cbd0d Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 27 Aug 2014 19:58:56 +0300 Subject: iwlwifi: mvm: Fix skip over dtim configuration in d0i3 There was some confusion concerning the units of the beacon interval. The driver assumed that it was in msec where it was in TU - so fix that. Skip over dtim was capped by 300TU where it should be by 306TU. It should also be subjected to several conditions: Not a DFS channel, dtim period < 10, and the multicast wake-lock is off. Concerning multicast lock - there is an implementation gap in the supplicant, so just leave a TODO. Signed-off-by: Avri Altman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 5a29c19..ff842ee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -286,12 +286,28 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, return true; } +static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; + bool radar_detect = false; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(vif->chanctx_conf); + WARN_ON(!chanctx_conf); + if (chanctx_conf) { + chan = chanctx_conf->def.chan; + radar_detect = chan->flags & IEEE80211_CHAN_RADAR; + } + rcu_read_unlock(); + + return radar_detect; +} + static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mac_power_cmd *cmd) { - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; int dtimper, dtimper_msec; int keep_alive; bool radar_detect = false; @@ -333,14 +349,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, } /* Check if radar detection is required on current channel */ - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); - WARN_ON(!chanctx_conf); - if (chanctx_conf) { - chan = chanctx_conf->def.chan; - radar_detect = chan->flags & IEEE80211_CHAN_RADAR; - } - rcu_read_unlock(); + radar_detect = iwl_mvm_power_is_radar(vif); /* Check skip over DTIM conditions */ if (!radar_detect && (dtimper <= 10) && @@ -961,17 +970,22 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { - /* configure skip over dtim up to 300 msec */ + /* configure skip over dtim up to 306TU - 314 msec */ int dtimper = vif->bss_conf.dtim_period ?: 1; - int dtimper_msec = dtimper * vif->bss_conf.beacon_int; + int dtimper_tu = dtimper * vif->bss_conf.beacon_int; + bool radar_detect = iwl_mvm_power_is_radar(vif); - if (WARN_ON(!dtimper_msec)) + if (WARN_ON(!dtimper_tu)) return 0; - cmd.skip_dtim_periods = 300 / dtimper_msec; - if (cmd.skip_dtim_periods) - cmd.flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + /* Check skip over DTIM conditions */ + /* TODO: check that multicast wake lock is off */ + if (!radar_detect && (dtimper < 10)) { + cmd.skip_dtim_periods = 306 / dtimper_tu; + if (cmd.skip_dtim_periods) + cmd.flags |= cpu_to_le16( + POWER_FLAGS_SKIP_OVER_DTIM_MSK); + } } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v0.10.2 From 9474d444bd0e6590ba99d640fa5e4d28380c1f04 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 3 Sep 2014 12:09:45 +0300 Subject: iwlwifi: mvm: fix PSM disable during TDLS Simplify the code and check for TDLS stations just before sending the MAC_POWER_TABLE command. The previous version of the code still allowed PM in some multi-interface scenarios even with TDLS connected. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index ff842ee..5b85b0c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -336,7 +336,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - !mvmvif->pm_enabled) + !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -510,8 +510,6 @@ struct iwl_power_vifs { bool bss_active; bool ap_active; bool monitor_active; - bool bss_tdls; - bool p2p_tdls; }; static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac, @@ -566,8 +564,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->p2p_vif); power_iterator->p2p_vif = vif; - power_iterator->p2p_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->p2p_active = true; @@ -577,8 +573,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, /* only a single MAC of the same type */ WARN_ON(power_iterator->bss_vif); power_iterator->bss_vif = vif; - power_iterator->bss_tdls = - !!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif); if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt->id < MAX_PHYS) power_iterator->bss_active = true; @@ -621,15 +615,13 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active && - !vifs->bss_tdls) { + if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active && - !vifs->p2p_tdls) { + if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM) p2p_mvmvif->pm_enabled = true; return; -- cgit v0.10.2 From 4cb832d559416605d2a863fa34f362c31d174cc3 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 6 Aug 2014 10:52:27 +0300 Subject: iwlwifi: mvm: move IWL_MVM_UAPSD_QUEUES to constants.h Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 1181089..a355788 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -65,12 +65,18 @@ #ifndef __MVM_CONSTANTS_H #define __MVM_CONSTANTS_H +#include + #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) +#define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index a3bb4a0..2517f87 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -327,7 +327,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 && !iwlwifi_mod_params.uapsd_disable) { hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_UAPSD_AC_INFO; + hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 6eb1f85..efdafa1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -180,10 +180,6 @@ enum iwl_power_scheme { }; #define IWL_CONN_MAX_LISTEN_INTERVAL 10 -#define IWL_UAPSD_AC_INFO (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_2 #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v0.10.2 From f991e17ba2584e2be66476cc468f19769efd55cc Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 26 Aug 2014 16:14:10 +0300 Subject: iwlwifi: mvm: align CSA GO NOA time event naming with the firmware The time event used for CSA GO will also be used by CSA client. Rename the symbols to something more generic and aligned with the firmware code. Signed-off-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index fbcc036..a2c6628 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -554,7 +554,7 @@ enum iwl_time_event_type { TE_WIDI_TX_SYNC, /* Channel Switch NoA */ - TE_P2P_GO_CSA_NOA, + TE_CHANNEL_SWITCH_PERIOD, TE_MAX }; /* MAC_EVENT_TYPE_API_E_VER_1 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 158aed5..8342671 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1234,13 +1234,13 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { u32 rel_time = (c + 1) * csa_vif->bss_conf.beacon_int - - IWL_MVM_CHANNEL_SWITCH_TIME; + IWL_MVM_CHANNEL_SWITCH_TIME_GO; u32 apply_time = gp2 + rel_time * 1024; - iwl_mvm_schedule_csa_noa(mvm, csa_vif, - IWL_MVM_CHANNEL_SWITCH_TIME - - IWL_MVM_CHANNEL_SWITCH_MARGIN, - apply_time); + iwl_mvm_schedule_csa_period(mvm, csa_vif, + IWL_MVM_CHANNEL_SWITCH_TIME_GO - + IWL_MVM_CHANNEL_SWITCH_MARGIN, + apply_time); } } else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { /* we don't have CSA NoA scheduled yet, switch now */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index efdafa1..5529958 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -87,11 +87,11 @@ /* A TimeUnit is 1024 microsecond */ #define MSEC_TO_TU(_msec) (_msec*1000/1024) -/* - * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0" - * TBTT. This value should be big enough to ensure that we switch in time. +/* This value represents the number of TUs before CSA "beacon 0" TBTT + * when the CSA time-event needs to be scheduled to start. It must be + * big enough to ensure that we switch in time. */ -#define IWL_MVM_CHANNEL_SWITCH_TIME 40 +#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 /* * This value (in TUs) is used to fine tune the CSA NoA end time which should diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 447d3b1..b7f9e61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -700,9 +700,9 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) iwl_mvm_roc_finished(mvm); } -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time) +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; @@ -711,14 +711,14 @@ int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (te_data->running) { - IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n"); + IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); return -EBUSY; } time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); - time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA); + time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD); time_cmd.apply_time = cpu_to_le32(apply_time); time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.duration = cpu_to_le32(duration); diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index bee3b24..b350e47 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -219,7 +219,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, void iwl_mvm_roc_done_wk(struct work_struct *wk); /** - * iwl_mvm_schedule_csa_noa - request NoA for channel switch + * iwl_mvm_schedule_csa_period - request channel switch absence period * @mvm: the mvm component * @vif: the virtual interface for which the channel switch is issued * @duration: the duration of the NoA in TU. @@ -228,9 +228,9 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk); * This function is used to schedule NoA time event and is used to perform * the channel switch flow. */ -int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - u32 duration, u32 apply_time); +int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 apply_time); /** * iwl_mvm_te_scheduled - check if the fw received the TE cmd -- cgit v0.10.2 From 62c5afb8e388eae4e54f1ad415c1a1bc745c8b08 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 5 Sep 2014 17:30:16 +0300 Subject: hostap: proc: substitute loops by %*phN For dumping small buffers we may use %*phN specifier instead of custom approach.. Signed-off-by: Andy Shevchenko Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index 4e5c0f8..8efd17c 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -186,11 +186,9 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v) bss->ssid[i] : '_'); seq_putc(m, '\t'); - for (i = 0; i < bss->ssid_len; i++) - seq_printf(m, "%02x", bss->ssid[i]); + seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid); seq_putc(m, '\t'); - for (i = 0; i < bss->wpa_ie_len; i++) - seq_printf(m, "%02x", bss->wpa_ie[i]); + seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie); seq_putc(m, '\n'); return 0; } -- cgit v0.10.2 From 4307b0fe22f4641530bc24066dc432e3f1125459 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 11 Sep 2014 23:50:54 +0200 Subject: ath9k: fix radar parameters initialization Move ath9k_hw_set_radar_params() in ath9k_hw_reset() in order to avoid AR_PHY_RADAR registers are overwritten after hw reset Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index a1b3282..d2a0f12 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -83,8 +83,6 @@ static int ath_set_channel(struct ath_softc *sc) if (hw->conf.radar_enabled) { u32 rxfilter; - /* set HW specific DFS configuration */ - ath9k_hw_set_radar_params(ah); rxfilter = ath9k_hw_getrxfilter(ah); rxfilter |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 69bbea1..ef5f5a6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1954,6 +1954,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9565(ah) && common->bt_ant_diversity) REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); + if (ah->hw->conf.radar_enabled) { + /* set HW specific DFS configuration */ + ath9k_hw_set_radar_params(ah); + } + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); -- cgit v0.10.2 From 6b5447ce630cdc231caf4f958325f8fa925216bf Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 11 Sep 2014 19:02:10 -0500 Subject: rtlwifi: btcoexist: avoid format string in printk Recent changes to this driver inadvertently reverted the change made by Kees Cook in commit 6437f51ec3. Reported-by: Kees Cook Signed-off-by: Larry Finger Cc: Kees Cook Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index 0d185e6..bd03b8c 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -117,7 +117,7 @@ extern u32 btc_dbg_type[]; #define WIFI_P2P_GC_CONNECTED BIT4 #define CL_SPRINTF snprintf -#define CL_PRINTF printk +#define CL_PRINTF(buf) printk("%s", buf) #define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ do { \ -- cgit v0.10.2 From 48bf43fad76eb656f55bff3e3febe91578f1afe3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 12 Sep 2014 12:10:48 +0530 Subject: ath9k: Fix beacon processing in offchannel When interfaces of different types are present in a context and an offchannel request is received on a STA interface, we end up trying to process beacons received when we are offchannel. This hits the below warning since offchannel will not have proper beacon parameters. Fix this by not processing beacons received when we are offchannel. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 0 at ../drivers/net/wireless/ath/ath9k/recv.c:552 ath_rx_tasklet+0xf8f/0x1020 [ath9k]() CPU: 1 PID: 0 Comm: swapper/1 Tainted: G O 3.17.0-rc4-wl-debug #16 Hardware name: LENOVO 28427ZQ/INVALID, BIOS 6JET58WW (1.16 ) 09/17/2009 0000000000000000 15916787056abba3 ffff88013b603d08 ffffffff8156af94 ffff88013b603d50 ffff88013b603d40 ffffffff81070dbd ffff8800a84bb300 ffff8800b05db358 ffff8800a84cc578 ffff8800a84bb300 ffff8800b05daa40 Call Trace: [] dump_stack+0x4d/0x6f [] warn_slowpath_common+0x7d/0xa0 [] warn_slowpath_fmt+0x5c/0x80 [] ? _raw_spin_lock_irqsave+0x83/0xa0 [] ? ath_rx_tasklet+0x9f6/0x1020 [ath9k] [] ath_rx_tasklet+0xf8f/0x1020 [ath9k] [] ath9k_tasklet+0xf4/0x310 [ath9k] [] tasklet_action+0xe7/0xf0 [] __do_softirq+0x12a/0x340 [] irq_exit+0x9e/0xc0 [] do_IRQ+0x56/0xe0 [] common_interrupt+0x72/0x72 [] ? cpuidle_enter_state+0x67/0x1a0 [] cpuidle_enter+0x17/0x20 [] cpu_startup_entry+0x3ce/0x420 [] start_secondary+0x233/0x2c0 ---[ end trace f15c3e33ba78d840 ]--- ------------[ cut here ]------------ Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 957a877..dea8e1b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -537,6 +537,7 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool skip_beacon = false; if (skb->len < 24 + 8 + 2 + 2) return; @@ -547,7 +548,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) + + if (ath9k_is_chanctx_enabled()) { + if (sc->cur_chan == &sc->offchannel.chan) + skip_beacon = true; + } + + if (!skip_beacon && + !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) ath9k_set_beacon(sc); ath9k_p2p_beacon_sync(sc); -- cgit v0.10.2 From 1f21de53ac8651b1a3e79576f1adf00aabecd052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Sep 2014 10:24:10 +0200 Subject: b43: HT-PHY: Implement band switching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It works pretty much the same way as in N-PHY. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 95a9433..a980595 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -476,6 +476,11 @@ enum { #define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */ #define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */ +/* B43_MMIO_PSM_PHY_HDR bits */ +#define B43_PSM_HDR_MAC_PHY_RESET 0x00000001 +#define B43_PSM_HDR_MAC_PHY_CLOCK_EN 0x00000002 +#define B43_PSM_HDR_MAC_PHY_FORCE_CLK 0x00000004 + /* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */ #define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100 #define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200 diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index a379602..6a0140a 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -321,6 +321,26 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } +static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset) +{ + u16 tmp; + + tmp = b43_read16(dev, B43_MMIO_PSM_PHY_HDR); + b43_write16(dev, B43_MMIO_PSM_PHY_HDR, + tmp | B43_PSM_HDR_MAC_PHY_FORCE_CLK); + + /* Put BPHY in or take it out of the reset */ + if (reset) + b43_phy_set(dev, B43_PHY_B_BBCFG, + B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX); + else + b43_phy_mask(dev, B43_PHY_B_BBCFG, + (u16)~(B43_PHY_B_BBCFG_RSTCCA | + B43_PHY_B_BBCFG_RSTRX)); + + b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp); +} + /************************************************** * Samples **************************************************/ @@ -757,13 +777,19 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev, const struct b43_phy_ht_channeltab_e_phy *e, struct ieee80211_channel *new_channel) { - bool old_band_5ghz; + if (new_channel->band == IEEE80211_BAND_5GHZ) { + /* Switch to 2 GHz for a moment to access B-PHY regs */ + b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ); + + b43_phy_ht_bphy_reset(dev, true); + + /* Switch to 5 GHz */ + b43_phy_set(dev, B43_PHY_HT_BANDCTL, B43_PHY_HT_BANDCTL_5GHZ); + } else { + /* Switch to 2 GHz */ + b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ); - old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */ - if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) { - /* TODO */ - } else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) { - /* TODO */ + b43_phy_ht_bphy_reset(dev, false); } b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1); diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h index 67b208e..c086f56 100644 --- a/drivers/net/wireless/b43/phy_ht.h +++ b/drivers/net/wireless/b43/phy_ht.h @@ -106,6 +106,9 @@ #define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0 #define B43_PHY_HT_TX_PCTL_STATUS_C3 B43_PHY_EXTG(0x169) +#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) +#define B43_PHY_B_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_B_BBCFG_RSTRX 0x8000 /* Reset RX */ #define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A) -- cgit v0.10.2 From 5effb73c529c5d66eecd541d30470b11cc58c64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Sep 2014 10:24:11 +0200 Subject: b43: HT-PHY: Update values for frequency calibration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous values were extracted from MMIO dump of some old 5.x driver, new ones should improve calibration. This also adds values for 5 GHz. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c index b2a53b2..a3cf9ef 100644 --- a/drivers/net/wireless/b43/radio_2059.c +++ b/drivers/net/wireless/b43/radio_2059.c @@ -65,73 +65,87 @@ static u16 r2059_phy_rev1_init[][2] = { .phy_regs.bw5 = r4, \ .phy_regs.bw6 = r5 +/* Extracted from MMIO dump of 6.30.223.141 + * TODO: Values for channels 12 & 13 are outdated (from some old 5.x driver)! + */ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = { - { .freq = 2412, - RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, - 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), - }, - { .freq = 2417, - RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, - 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), - }, - { .freq = 2422, - RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, - 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), - }, - { .freq = 2427, - RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, - 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), - }, - { .freq = 2432, - RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, - 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), - }, - { .freq = 2437, - RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, - 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), - }, - { .freq = 2442, - RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), - }, - { .freq = 2447, - RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), - }, - { .freq = 2452, - RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, - 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), - }, - { .freq = 2457, - RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, - 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), - }, - { .freq = 2462, - RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, - 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03, - 0x00, 0x00, 0x00, 0xf0, 0x00), - PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), - }, + { + .freq = 2412, + RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443), + }, + { + .freq = 2417, + RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, + 0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441), + }, + { + .freq = 2422, + RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xd0, 0x00), + PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f), + }, + { + .freq = 2427, + RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, + 0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d), + }, + { + .freq = 2432, + RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a), + }, + { + .freq = 2437, + RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, + 0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0xa0, 0x00), + PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438), + }, + { + .freq = 2442, + RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436), + }, + { + .freq = 2447, + RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434), + }, + { + .freq = 2452, + RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, + 0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x80, 0x00), + PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431), + }, + { + .freq = 2457, + RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x60, 0x00), + PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f), + }, + { + .freq = 2462, + RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, + 0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x60, 0x00), + PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d), + }, { .freq = 2467, RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03, @@ -144,6 +158,174 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi 0x00, 0x00, 0x00, 0xf0, 0x00), PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429), }, + { + .freq = 5180, + RADIOREGS(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0xa3, 0x00, 0xfc), + PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb), + }, + { + .freq = 5200, + RADIOREGS(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xfb), + PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9), + }, + { + .freq = 5220, + RADIOREGS(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xea), + PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7), + }, + { + .freq = 5240, + RADIOREGS(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c, + 0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xda), + PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5), + }, + { + .freq = 5260, + RADIOREGS(0xd9, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0e, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xca), + PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3), + }, + { + .freq = 5280, + RADIOREGS(0xe0, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x10, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4f, 0x93, 0x00, 0xb9), + PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1), + }, + { + .freq = 5300, + RADIOREGS(0xe6, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x12, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4c, 0x83, 0x00, 0xb8), + PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0), + }, + { + .freq = 5320, + RADIOREGS(0xed, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x14, + 0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00, + 0x0f, 0x4c, 0x83, 0x00, 0xa8), + PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee), + }, + { + .freq = 5500, + RADIOREGS(0x29, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x26, + 0x02, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd), + }, + { + .freq = 5520, + RADIOREGS(0x30, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x28, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc), + }, + { + .freq = 5540, + RADIOREGS(0x36, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2a, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da), + }, + { + .freq = 5560, + RADIOREGS(0x3d, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2c, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x75), + PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8), + }, + { + .freq = 5580, + RADIOREGS(0x44, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2e, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x0a, 0x46, 0x43, 0x00, 0x74), + PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7), + }, + { + .freq = 5600, + RADIOREGS(0x4a, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x30, + 0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x54), + PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5), + }, + { + .freq = 5620, + RADIOREGS(0x51, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x32, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x54), + PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3), + }, + { + .freq = 5640, + RADIOREGS(0x58, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x34, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x44, 0x23, 0x00, 0x43), + PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2), + }, + { + .freq = 5660, + RADIOREGS(0x5e, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x36, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x43, 0x23, 0x00, 0x43), + PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0), + }, + { + .freq = 5680, + RADIOREGS(0x65, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x38, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x09, 0x42, 0x23, 0x00, 0x43), + PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce), + }, + { + .freq = 5700, + RADIOREGS(0x6c, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x3a, + 0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x32), + PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd), + }, + { + .freq = 5745, + RADIOREGS(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d, + 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x21), + PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9), + }, + { + .freq = 5765, + RADIOREGS(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81, + 0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x11), + PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8), + }, + { + .freq = 5785, + RADIOREGS(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x08, 0x42, 0x13, 0x00, 0x00), + PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6), + }, + { + .freq = 5805, + RADIOREGS(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x06, 0x41, 0x03, 0x00, 0x00), + PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4), + }, + { + .freq = 5825, + RADIOREGS(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d, + 0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00, + 0x06, 0x41, 0x03, 0x00, 0x00), + PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3), + }, }; void r2059_upload_inittabs(struct b43_wldev *dev) -- cgit v0.10.2 From 4721c63b929b13bce6860dc8ec068f86efcab2ea Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:45 +0530 Subject: mwifiex: set fw api info for backword compatibility If we dont set FW API info here, for older FW releases where FW API is not available in GET_HW_SPEC, API version would remain 0. This may cause issues with 11ac if older FW is used with newer driver. Signed-off-by: Avinash Patil Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 985f6c2..fcc70ae 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1508,6 +1508,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, } adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff; adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) { -- cgit v0.10.2 From 3c99832d74777c9ec5545a92450fac5d37b0d0e1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:46 +0530 Subject: mwifiex: fix probable memory corruption while processing TDLS frame Size of RSN IE buffer in driver is 254 while maximum size of received buffer to be copied to RSN IE buffer can be 255. Add boundary check to copy maximum of 254 bytes into RSN IE buffer. Reported-by: Dan Carpenter Signed-off-by: Avinash Patil Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 4c5fd95..e294907 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -871,7 +871,9 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, break; case WLAN_EID_RSN: memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, - sizeof(struct ieee_types_header) + pos[1]); + sizeof(struct ieee_types_header) + + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: sta_ptr->tdls_cap.qos_info = pos[2]; -- cgit v0.10.2 From 42a028aa952b66a039ee8c0a08ff4e3658246269 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:47 +0530 Subject: mwifiex: avoid processing RX packets with invalid length If rx_len received in interface header from FW is more than RX buffer size, skb_put for such length results into skb_panic. Avoid this by not processing such packets. We just print a warning for such packets and free skb. Reviewed-by: Paul Stewart Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Marc Yang Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index ff05458..27c2bf8 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1271,12 +1271,20 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) */ pkt_len = *((__le16 *)skb_data->data); rx_len = le16_to_cpu(pkt_len); - skb_put(skb_data, rx_len); - dev_dbg(adapter->dev, - "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", - card->rxbd_rdptr, wrptr, rx_len); - skb_pull(skb_data, INTF_HEADER_LEN); - mwifiex_handle_rx_packet(adapter, skb_data); + if (WARN_ON(rx_len <= INTF_HEADER_LEN || + rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) { + dev_err(adapter->dev, + "Invalid RX len %d, Rd=%#x, Wr=%#x\n", + rx_len, card->rxbd_rdptr, wrptr); + dev_kfree_skb_any(skb_data); + } else { + skb_put(skb_data, rx_len); + dev_dbg(adapter->dev, + "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", + card->rxbd_rdptr, wrptr, rx_len); + skb_pull(skb_data, INTF_HEADER_LEN); + mwifiex_handle_rx_packet(adapter, skb_data); + } skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); if (!skb_tmp) { -- cgit v0.10.2 From 3223db2086c987d4527fdaa487a027b0148e9692 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:48 +0530 Subject: mwifiex: rework internal scan for association There was an issue with internal scan during association wherein we would complete internal scan on first scan command response. This would cause association failure if AP is not found in first scan response e.g. APs from A band. This patch fixes this issue by completing internal scan only when all scan commands from scan pending queue and command pending queue are sent to FW and response to last scan command is received. Tested-by: Xinmin Hu Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 195ef0ca..0c9ed2c 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1971,9 +1971,34 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, /* This function handles the command response of extended scan */ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv) { + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_command *cmd_ptr; + struct cmd_ctrl_node *cmd_node; + unsigned long cmd_flags, scan_flags; + bool complete_scan = false; + dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n"); - mwifiex_complete_scan(priv); + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags); + spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags); + if (list_empty(&adapter->scan_pending_q)) { + complete_scan = true; + list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { + cmd_ptr = (void *)cmd_node->cmd_skb->data; + if (le16_to_cpu(cmd_ptr->command) == + HostCmd_CMD_802_11_SCAN_EXT) { + dev_dbg(priv->adapter->dev, + "Scan pending in command pending list"); + complete_scan = false; + break; + } + } + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_flags); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_flags); + + if (complete_scan) + mwifiex_complete_scan(priv); return 0; } -- cgit v0.10.2 From 2703a66865eb3a5b422749281371e9eefa8658c4 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:49 +0530 Subject: mwifiex: support for event done interrupt This patch adds support for writing CPU event interrupt done back to device. Patch also increases interrupt buffer ring size from 4 to 8. Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 27c2bf8..2ada1b7 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1726,6 +1726,13 @@ static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) buffer is released. This is just to make things simpler, we need to find a better method of managing these buffers. */ + } else { + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_EVENT_DONE)) { + dev_warn(adapter->dev, + "Write register failed\n"); + return -1; + } } return 0; diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index a1a8fd3..200e8b0 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -40,8 +40,8 @@ #define MWIFIEX_TXBD_MASK 0x3F #define MWIFIEX_RXBD_MASK 0x3F -#define MWIFIEX_MAX_EVT_BD 0x04 -#define MWIFIEX_EVTBD_MASK 0x07 +#define MWIFIEX_MAX_EVT_BD 0x08 +#define MWIFIEX_EVTBD_MASK 0x0f /* PCIE INTERNAL REGISTERS */ #define PCIE_SCRATCH_0_REG 0xC10 @@ -69,6 +69,7 @@ #define CPU_INTR_DOOR_BELL BIT(1) #define CPU_INTR_SLEEP_CFM_DONE BIT(2) #define CPU_INTR_RESET BIT(3) +#define CPU_INTR_EVENT_DONE BIT(5) #define HOST_INTR_DNLD_DONE BIT(0) #define HOST_INTR_UPLD_RDY BIT(1) -- cgit v0.10.2 From a659c4306b3d8de0be218ad47ee92eae31d5b0dd Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Fri, 12 Sep 2014 20:08:50 +0530 Subject: mwifiex: fix 5G association failure after leaving 2.4G IBSS When assocaiting to an AP , mwifiex set supported data rates based on target AP's capability. For 5G AP(11a mode), a/n/ac mode would possibly be set. However, for some chips which dont support 11AC mode current config_bands will be used instead. For example, if we join an IBSS in 11b mode ,adapter->config_bands will be set to 1(11b mode). Then we leave IBSS ,and try to connect 5G a/n mode AP. At this time , only 11b mode data rates will be supported in assoc request , which result in assoc failure with reason code 18: Association denied due to requesting station not supporting all rates. This patch fix such a cornel case, by adding additional check for current chip's 11ac capability. Reported-by: Andreas Fenkart Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index b95a29b..92f3eb8 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -287,10 +287,13 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, return -1; if (mwifiex_band_to_radio_type(bss_desc->bss_band) == - HostCmd_SCAN_RADIO_TYPE_BG) + HostCmd_SCAN_RADIO_TYPE_BG) { config_bands = BAND_B | BAND_G | BAND_GN; - else - config_bands = BAND_A | BAND_AN | BAND_AAC; + } else { + config_bands = BAND_A | BAND_AN; + if (adapter->fw_bands & BAND_AAC) + config_bands |= BAND_AAC; + } if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) adapter->config_bands = config_bands; -- cgit v0.10.2 From c7346c3231e9b8e530ab7b73796066f7bf60b240 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 12 Sep 2014 20:08:51 +0530 Subject: mwifiex: fix a bug in Tx multiport aggregation When aggregation port limit is reached, we stop aggregation and the data is sent to firmware. It is observed that one less packet than the port limit is aggregated in this case. ex. 15 instead of 16. The reason is we have redundant port limit checks before current packet is added to aggregation buffer. The issue is fixed by removing these checks. We already have necessary check in precopy current buffer handling. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 1770fa3..993841e 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1527,8 +1527,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, __func__); if (MP_TX_AGGR_IN_PROGRESS(card)) { - if (!mp_tx_aggr_port_limit_reached(card) && - MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { f_precopy_cur_buf = 1; if (!(card->mp_wr_bitmap & @@ -1540,8 +1539,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, /* No room in Aggr buf, send it */ f_send_aggr_buf = 1; - if (mp_tx_aggr_port_limit_reached(card) || - !(card->mp_wr_bitmap & + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) f_send_cur_buf = 1; else -- cgit v0.10.2 From c48ba040acb81bc37ead17cae23fe3d9b3c08474 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 12 Sep 2014 20:08:52 +0530 Subject: mwifiex: minor cleanup in multiport aggregation 'mp_data_port_mask' and 'mp_end_port' gives correct information even for the chipsets supporting SDIO new mode (32 ports). We will get rid of this chip specific handling. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 993841e..bdab122 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -622,22 +622,15 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port) dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); - if (card->supports_sdio_new_mode && - !(wr_bitmap & reg->data_port_mask)) { + if (!(wr_bitmap & card->mp_data_port_mask)) { adapter->data_sent = true; return -EBUSY; - } else if (!card->supports_sdio_new_mode && - !(wr_bitmap & card->mp_data_port_mask)) { - return -1; } if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port)); *port = card->curr_wr_port; - if (((card->supports_sdio_new_mode) && - (++card->curr_wr_port == card->max_ports)) || - ((!card->supports_sdio_new_mode) && - (++card->curr_wr_port == card->mp_end_port))) + if (++card->curr_wr_port == card->mp_end_port) card->curr_wr_port = reg->start_wr_port; } else { adapter->data_sent = true; -- cgit v0.10.2 From a9c1c89eea11884243825d473fd3991d943ffc65 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:53 +0530 Subject: mwifiex: set passive scan type for scan requests with no ssid It was observed that station would sent probe request even when scan type has been set as passive during iw scan. This was happening because driver sets passive scan type only when channel has IEEE80211_CHAN_NO_IR flag set. Along with this, add condition to check if no ssids are specified in scan request so as to mark such scan request passive. Signed-off-by: Avinash Patil Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c4723b0..740f7d0 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1981,7 +1981,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].chan_number = chan->hw_value; user_scan_cfg->chan_list[i].radio_type = chan->band; - if (chan->flags & IEEE80211_CHAN_NO_IR) + if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else -- cgit v0.10.2 From cb91be87e12c079fcf25069a21123756c0931dd6 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:54 +0530 Subject: mwifiex: bring in scan channel gap feature With scan channel gap when any station/AP is active, FW comes back to connected channel for any pending data transfter after scanning each channel. We set scan channel gap TLV to FW in scan command when any of the interface is active. This enables scan channel gap in FW. Also when scan channel gap is enabled, we would scan maximum channels allowed by FW. Scan channel gap is supported only on FW with V15 FW API. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 740f7d0..2066abb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1991,6 +1991,11 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].scan_time = 0; } + if (priv->adapter->scan_chan_gap_enabled && + mwifiex_is_any_intf_active(priv)) + user_scan_cfg->scan_chan_gap = + priv->adapter->scan_chan_gap_time; + ret = mwifiex_scan_networks(priv, user_scan_cfg); kfree(user_scan_cfg); if (ret) { diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index fcc70ae..8559720 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1613,5 +1613,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, adapter->if_ops.update_mp_end_port(adapter, le16_to_cpu(hw_spec->mp_end_port)); + if (adapter->fw_api_ver == MWIFIEX_FW_V15) + adapter->scan_chan_gap_enabled = true; + return 0; } diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6a703ea..1eb6173 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -170,7 +170,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) -#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) +#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) +#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -653,6 +654,12 @@ struct mwifiex_ie_types_num_probes { __le16 num_probes; } __packed; +struct mwifiex_ie_types_scan_chan_gap { + struct mwifiex_ie_types_header header; + /* time gap in TUs to be used between two consecutive channels scan */ + __le16 chan_gap; +} __packed; + struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; @@ -1249,6 +1256,7 @@ struct mwifiex_user_scan_cfg { u8 num_ssids; /* Variable number (fixed maximum) of channels to scan up */ struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; + u16 scan_chan_gap; } __packed; struct ie_body { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 80bda80..d99c6f6 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -212,6 +212,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; + adapter->scan_chan_gap_time = MWIFIEX_DEF_SCAN_CHAN_GAP_TIME; adapter->scan_probes = 1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5439963..c3d097c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -84,6 +84,7 @@ enum { #define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110 #define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 30 #define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 30 +#define MWIFIEX_DEF_SCAN_CHAN_GAP_TIME 50 #define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) @@ -770,6 +771,7 @@ struct mwifiex_adapter { u16 specific_scan_time; u16 active_scan_time; u16 passive_scan_time; + u16 scan_chan_gap_time; u8 fw_bands; u8 adhoc_start_band; u8 config_bands; @@ -839,6 +841,7 @@ struct mwifiex_adapter { struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; + bool scan_chan_gap_enabled; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); @@ -1139,6 +1142,25 @@ mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv) return priv->csa_chan; } +static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv) +{ + struct mwifiex_private *priv_num; + int i; + + for (i = 0; i < priv->adapter->priv_num; i++) { + priv_num = priv->adapter->priv[i]; + if (priv_num) { + if ((GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_UAP && + priv_num->bss_started) || + (GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_STA && + priv_num->media_connected)) + return 1; + } + } + + return 0; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); @@ -1274,6 +1296,7 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv); bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv); u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band, u32 pri_chan, u8 chan_bw); +int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 0c9ed2c..2f86bb6 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -799,6 +799,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv; struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; struct mwifiex_ie_types_bssid_list *bssid_tlv; u8 *tlv_pos; @@ -939,6 +940,22 @@ mwifiex_config_scan(struct mwifiex_private *priv, else *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + if (user_scan_in->scan_chan_gap) { + *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; + dev_dbg(adapter->dev, "info: scan: channel gap = %d\n", + user_scan_in->scan_chan_gap); + + chan_gap_tlv = (void *)tlv_pos; + chan_gap_tlv->header.type = + cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP); + chan_gap_tlv->header.len = + cpu_to_le16(sizeof(chan_gap_tlv->chan_gap)); + chan_gap_tlv->chan_gap = + cpu_to_le16((user_scan_in->scan_chan_gap)); + + tlv_pos += sizeof(struct mwifiex_ie_types_scan_chan_gap); + } + /* If the input config or adapter has the number of Probes set, add tlv */ if (num_probes) { -- cgit v0.10.2 From 97010cf8dfe5ca2d9f5d8d32a0e1f25246f852ea Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:55 +0530 Subject: mwifiex: remove restriction of single channel scan when connected With scan channel gap in place, FW comes back to connected channel after each scan; so we dont need to restrict FW to scan single channel while connected. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 2f86bb6..183528d 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1067,12 +1067,6 @@ mwifiex_config_scan(struct mwifiex_private *priv, *filtered_scan); } - /* - * In associated state we will reduce the number of channels scanned per - * scan command to 1 to avoid any traffic delay/loss. - */ - if (priv->media_connected) - *max_chan_per_scan = 1; } /* -- cgit v0.10.2 From 5ec39efa16036c8291d2d81282280213c2c16ad1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:56 +0530 Subject: mwifiex: process TX even when scan is ongoing With channel scan gap, FW comes back to connected channel after each single channel scan. So we can safely transfer data to FW during scan. FW would send this data once on connected channel. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index dfa37ea..d6d2342 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -284,8 +284,9 @@ process_start: adapter->tx_lock_flag) break; - if ((adapter->scan_processing && - !adapter->scan_delay_cnt) || adapter->data_sent || + if ((!adapter->scan_chan_gap_enabled && + !adapter->scan_delay_cnt && + adapter->scan_processing) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) @@ -339,7 +340,8 @@ process_start: } } - if ((!adapter->scan_processing || adapter->scan_delay_cnt) && + if ((adapter->scan_chan_gap_enabled || + (!adapter->scan_processing || adapter->scan_delay_cnt)) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { -- cgit v0.10.2 From 971a73f5523ea0512267949bd6ae3f68b9f3431f Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 12 Sep 2014 20:08:57 +0530 Subject: mwifiex: remove redundant variable report_scan_result This variable is never used, get rid of it. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c3d097c..651fd8c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -548,7 +548,6 @@ struct mwifiex_private { u8 nick_name[16]; u16 current_key_index; struct semaphore async_sem; - u8 report_scan_result; struct cfg80211_scan_request *scan_request; u8 cfg_bssid[6]; struct wps wps; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 183528d..2d1a247 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1779,9 +1779,6 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) if (!adapter->ext_scan) mwifiex_complete_scan(priv); - if (priv->report_scan_result) - priv->report_scan_result = false; - if (priv->scan_request) { dev_dbg(adapter->dev, "info: notifying scan done\n"); cfg80211_scan_done(priv->scan_request, 0); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 62866b0..4aad446 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -85,8 +85,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - if (priv->report_scan_result) - priv->report_scan_result = false; break; case HostCmd_CMD_MAC_CONTROL: -- cgit v0.10.2 From d8d91253ba11bb6e98105c2bc88a40d08fac06ff Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 12 Sep 2014 20:08:58 +0530 Subject: mwifiex: remove low priority scan handling We have a logic in driver to delay or abort low priority scan to serve Tx traffic effectively. With scan channel gap support added, firmware now allows driver to send Tx data while scan operation is in progress. Hence low priority scan handling in driver is not required now. This patch removes related code. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2066abb..0dd6729 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1936,13 +1936,6 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); - if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && - atomic_read(&priv->wmm.tx_pkts_queued) >= - MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) { - dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n"); - return -EBUSY; - } - /* Block scan request if scan operation or scan cleanup when interface * is disabled is in process */ @@ -2920,7 +2913,6 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->features |= NL80211_FEATURE_HT_IBSS | NL80211_FEATURE_INACTIVITY_TIMER | - NL80211_FEATURE_LOW_PRIORITY_SCAN | NL80211_FEATURE_NEED_OBSS_SCAN; /* Reserve space for mwifiex specific private data for BSS */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index d99c6f6..cd9baad 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -281,7 +281,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; - adapter->empty_tx_q_cnt = 0; adapter->ext_scan = true; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index d6d2342..f139386 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -28,91 +28,6 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; static char *cal_data_cfg; module_param(cal_data_cfg, charp, 0); -static void scan_delay_timer_fn(unsigned long data) -{ - struct mwifiex_private *priv = (struct mwifiex_private *)data; - struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node, *tmp_node; - spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock; - unsigned long flags; - - if (adapter->surprise_removed) - return; - - if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT || - !adapter->scan_processing) { - /* - * Abort scan operation by cancelling all pending scan - * commands - */ - spin_lock_irqsave(scan_q_lock, flags); - list_for_each_entry_safe(cmd_node, tmp_node, - &adapter->scan_pending_q, list) { - list_del(&cmd_node->list); - mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - } - spin_unlock_irqrestore(scan_q_lock, flags); - - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = false; - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - - if (priv->scan_request) { - dev_dbg(adapter->dev, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } else { - priv->scan_aborting = false; - dev_dbg(adapter->dev, "info: scan already aborted\n"); - } - goto done; - } - - if (!atomic_read(&priv->adapter->is_tx_received)) { - adapter->empty_tx_q_cnt++; - if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) { - /* - * No Tx traffic for 200msec. Get scan command from - * scan pending queue and put to cmd pending queue to - * resume scan operation - */ - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_lock_irqsave(scan_q_lock, flags); - - if (list_empty(&adapter->scan_pending_q)) { - spin_unlock_irqrestore(scan_q_lock, flags); - goto done; - } - - cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); - list_del(&cmd_node->list); - spin_unlock_irqrestore(scan_q_lock, flags); - - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); - queue_work(adapter->workqueue, &adapter->main_work); - goto done; - } - } else { - adapter->empty_tx_q_cnt = 0; - } - - /* Delay scan operation further by 20msec */ - mod_timer(&priv->scan_delay_timer, jiffies + - msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); - adapter->scan_delay_cnt++; - -done: - if (atomic_read(&priv->adapter->is_tx_received)) - atomic_set(&priv->adapter->is_tx_received, false); - - return; -} - /* * This function registers the device and performs all the necessary * initializations. @@ -160,10 +75,6 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter->priv[i]->adapter = adapter; adapter->priv_num++; - - setup_timer(&adapter->priv[i]->scan_delay_timer, - scan_delay_timer_fn, - (unsigned long)adapter->priv[i]); } mwifiex_init_lock_list(adapter); @@ -207,7 +118,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { mwifiex_free_curr_bcn(adapter->priv[i]); - del_timer_sync(&adapter->priv[i]->scan_delay_timer); kfree(adapter->priv[i]); } } @@ -285,7 +195,6 @@ process_start: break; if ((!adapter->scan_chan_gap_enabled && - !adapter->scan_delay_cnt && adapter->scan_processing) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || @@ -341,7 +250,7 @@ process_start: } if ((adapter->scan_chan_gap_enabled || - (!adapter->scan_processing || adapter->scan_delay_cnt)) && + !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { @@ -600,9 +509,6 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) atomic_inc(&priv->adapter->tx_pending); mwifiex_wmm_add_buf_txqueue(priv, skb); - if (priv->adapter->scan_delay_cnt) - atomic_set(&priv->adapter->is_tx_received, true); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); return 0; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 651fd8c..e9cd4ab 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -90,12 +90,6 @@ enum { #define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) -#define MWIFIEX_MAX_SCAN_DELAY_CNT 50 -#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10 -#define MWIFIEX_SCAN_DELAY_MSEC 20 - -#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN 2 - #define RSN_GTK_OUI_OFFSET 2 #define MWIFIEX_OUI_NOT_PRESENT 0 @@ -561,7 +555,6 @@ struct mwifiex_private { u16 proberesp_idx; u16 assocresp_idx; u16 rsn_idx; - struct timer_list scan_delay_timer; u8 ap_11n_enabled; u8 ap_11ac_enabled; u32 mgmt_frame_mask; @@ -816,8 +809,6 @@ struct mwifiex_adapter { spinlock_t queue_lock; /* lock for tx queues */ u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u16 max_mgmt_ie_index; - u8 scan_delay_cnt; - u8 empty_tx_q_cnt; const struct firmware *cal_data; struct device_node *dt_node; @@ -829,7 +820,6 @@ struct mwifiex_adapter { u32 usr_dot_11ac_dev_cap_a; u32 usr_dot_11ac_mcs_support; - atomic_t is_tx_received; atomic_t pending_bridged_pkts; struct semaphore *card_sem; bool ext_scan; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 2d1a247..c09ebee 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1766,7 +1766,7 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv) static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node; + struct cmd_ctrl_node *cmd_node, *tmp_node; unsigned long flags; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); @@ -1787,37 +1787,36 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) priv->scan_aborting = false; dev_dbg(adapter->dev, "info: scan already aborted\n"); } - } else { - if ((priv->scan_aborting && !priv->scan_request) || - priv->scan_block) { - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; - mod_timer(&priv->scan_delay_timer, jiffies); - dev_dbg(priv->adapter->dev, - "info: %s: triggerring scan abort\n", __func__); - } else if (!mwifiex_wmm_lists_empty(adapter) && - (priv->scan_request && (priv->scan_request->flags & - NL80211_SCAN_FLAG_LOW_PRIORITY))) { - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - adapter->scan_delay_cnt = 1; - mod_timer(&priv->scan_delay_timer, jiffies + - msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); - dev_dbg(priv->adapter->dev, - "info: %s: deferring scan\n", __func__); - } else { - /* Get scan command from scan_pending_q and put to - * cmd_pending_q - */ - cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); + } else if ((priv->scan_aborting && !priv->scan_request) || + priv->scan_block) { + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + dev_dbg(adapter->dev, "info: scan already aborted\n"); } + } else { + /* Get scan command from scan_pending_q and put to + * cmd_pending_q + */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); } return; -- cgit v0.10.2 From 6e251174c77a28a4ebaad9be963843898b658039 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:08:59 +0530 Subject: mwifiex: add rx workqueue support This patch adds RX work queue support to mwifiex. Packets received are queued to internal queue which are then processed by scheduling a work item for RX process. RX work is enabled only on SMP systems. Reviewed-by: James Cameron Signed-off-by: Avinash Patil Signed-off-by: Marc Yang Signed-off-by: Cathy Luo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 06a2c21..4005707 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -183,6 +183,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, if (!tbl) return; + spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags); + priv->adapter->rx_locked = true; + if (priv->adapter->rx_processing) { + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + flush_workqueue(priv->adapter->rx_workqueue); + } else { + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + } + start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); @@ -194,6 +203,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv, kfree(tbl->rx_reorder_ptr); kfree(tbl); + + spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags); + priv->adapter->rx_locked = false; + spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags); + } /* diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index cd9baad..f7c97cf 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -447,8 +447,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->cmd_free_q_lock); spin_lock_init(&adapter->cmd_pending_q_lock); spin_lock_init(&adapter->scan_pending_q_lock); + spin_lock_init(&adapter->rx_q_lock); + spin_lock_init(&adapter->rx_proc_lock); skb_queue_head_init(&adapter->usb_rx_data_q); + skb_queue_head_init(&adapter->rx_data_q); for (i = 0; i < adapter->priv_num; ++i) { INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); @@ -614,6 +617,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) int ret = -EINPROGRESS; struct mwifiex_private *priv; s32 i; + unsigned long flags; struct sk_buff *skb; /* mwifiex already shutdown */ @@ -648,6 +652,21 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) } } + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + atomic_dec(&adapter->rx_pending); + priv = adapter->priv[rx_info->bss_num]; + if (priv) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + spin_lock(&adapter->mwifiex_lock); if (adapter->if_ops.data_complete) { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f139386..b522f7c 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -126,6 +126,42 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) return 0; } +static int mwifiex_process_rx(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + struct sk_buff *skb; + bool delay_main_work = adapter->delay_main_work; + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + if (adapter->rx_processing || adapter->rx_locked) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + goto exit_rx_proc; + } else { + adapter->rx_processing = true; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } + + /* Check for Rx data */ + while ((skb = skb_dequeue(&adapter->rx_data_q))) { + atomic_dec(&adapter->rx_pending); + if (adapter->delay_main_work && + (atomic_dec_return(&adapter->rx_pending) < + LOW_RX_PENDING)) { + adapter->delay_main_work = false; + queue_work(adapter->rx_workqueue, &adapter->rx_work); + } + mwifiex_handle_rx_packet(adapter, skb); + } + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_processing = false; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + + if (delay_main_work) + queue_work(adapter->workqueue, &adapter->main_work); +exit_rx_proc: + return 0; +} + /* * The main process. * @@ -163,6 +199,19 @@ process_start: (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) break; + /* If we process interrupts first, it would increase RX pending + * even further. Avoid this by checking if rx_pending has + * crossed high threshold and schedule rx work queue + * and then process interrupts + */ + if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) { + adapter->delay_main_work = true; + if (!adapter->rx_processing) + queue_work(adapter->rx_workqueue, + &adapter->rx_work); + break; + } + /* Handle pending interrupt if any */ if (adapter->int_status) { if (adapter->hs_activated) @@ -171,6 +220,9 @@ process_start: adapter->if_ops.process_int_status(adapter); } + if (adapter->rx_work_enabled && adapter->data_received) + queue_work(adapter->rx_workqueue, &adapter->rx_work); + /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && @@ -183,6 +235,7 @@ process_start: } if (IS_CARD_RX_RCVD(adapter)) { + adapter->data_received = false; adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; @@ -318,6 +371,12 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) flush_workqueue(adapter->workqueue); destroy_workqueue(adapter->workqueue); adapter->workqueue = NULL; + + if (adapter->rx_workqueue) { + flush_workqueue(adapter->rx_workqueue); + destroy_workqueue(adapter->rx_workqueue); + adapter->rx_workqueue = NULL; + } } /* @@ -732,6 +791,21 @@ int is_command_pending(struct mwifiex_adapter *adapter) } /* + * This is the RX work queue function. + * + * It handles the RX operations. + */ +static void mwifiex_rx_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, rx_work); + + if (adapter->surprise_removed) + return; + mwifiex_process_rx(adapter); +} + +/* * This is the main work queue function. * * It handles the main process, which in turn handles the complete @@ -787,6 +861,11 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->cmd_wait_q.status = 0; adapter->scan_wait_q_woken = false; + if (num_possible_cpus() > 1) { + adapter->rx_work_enabled = true; + pr_notice("rx work enabled, cpus %d\n", num_possible_cpus()); + } + adapter->workqueue = alloc_workqueue("MWIFIEX_WORK_QUEUE", WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1); @@ -794,6 +873,18 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_kmalloc; INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + + if (adapter->rx_work_enabled) { + adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE", + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 1); + if (!adapter->rx_workqueue) + goto err_kmalloc; + + INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); + } + if (adapter->if_ops.iface_work) INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index e9cd4ab..1a99999 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -58,6 +58,9 @@ enum { #define MAX_TX_PENDING 100 #define LOW_TX_PENDING 80 +#define HIGH_RX_PENDING 50 +#define LOW_RX_PENDING 20 + #define MWIFIEX_UPLD_SIZE (2312) #define MAX_EVENT_SIZE 2048 @@ -714,6 +717,12 @@ struct mwifiex_adapter { atomic_t cmd_pending; struct workqueue_struct *workqueue; struct work_struct main_work; + struct workqueue_struct *rx_workqueue; + struct work_struct rx_work; + bool rx_work_enabled; + bool rx_processing; + bool delay_main_work; + bool rx_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; /* spin lock for init/shutdown */ spinlock_t mwifiex_lock; @@ -754,6 +763,10 @@ struct mwifiex_adapter { struct list_head scan_pending_q; /* spin lock for scan_pending_q */ spinlock_t scan_pending_q_lock; + /* spin lock for RX queue */ + spinlock_t rx_q_lock; + /* spin lock for RX processing routine */ + spinlock_t rx_proc_lock; struct sk_buff_head usb_rx_data_q; u32 scan_processing; u16 region_code; @@ -831,6 +844,7 @@ struct mwifiex_adapter { u8 num_mem_types; u8 curr_mem_idx; bool scan_chan_gap_enabled; + struct sk_buff_head rx_data_q; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 2ada1b7..1504b16 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1233,6 +1233,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) struct sk_buff *skb_tmp = NULL; struct mwifiex_pcie_buf_desc *desc; struct mwifiex_pfu_buf_desc *desc2; + unsigned long flags; if (!mwifiex_pcie_ok_to_access_hw(adapter)) mwifiex_pm_wakeup_card(adapter); @@ -1283,7 +1284,16 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); skb_pull(skb_data, INTF_HEADER_LEN); - mwifiex_handle_rx_packet(adapter, skb_data); + if (adapter->rx_work_enabled) { + spin_lock_irqsave(&adapter->rx_q_lock, flags); + skb_queue_tail(&adapter->rx_data_q, skb_data); + spin_unlock_irqrestore(&adapter->rx_q_lock, + flags); + adapter->data_received = true; + atomic_inc(&adapter->rx_pending); + } else { + mwifiex_handle_rx_packet(adapter, skb_data); + } } skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index bdab122..ea8fc58 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1039,6 +1039,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb, u32 upld_typ) { u8 *cmd_buf; + unsigned long flags; __le16 *curr_ptr = (__le16 *)skb->data; u16 pkt_len = le16_to_cpu(*curr_ptr); @@ -1048,7 +1049,15 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, switch (upld_typ) { case MWIFIEX_TYPE_DATA: dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); - mwifiex_handle_rx_packet(adapter, skb); + if (adapter->rx_work_enabled) { + spin_lock_irqsave(&adapter->rx_q_lock, flags); + skb_queue_tail(&adapter->rx_data_q, skb); + spin_unlock_irqrestore(&adapter->rx_q_lock, flags); + adapter->data_received = true; + atomic_inc(&adapter->rx_pending); + } else { + mwifiex_handle_rx_packet(adapter, skb); + } break; case MWIFIEX_TYPE_CMD: -- cgit v0.10.2 From 50398ee03414228ba834a52aa4f203871a506b72 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 12 Sep 2014 20:09:00 +0530 Subject: mwifiex: modify TX/RX window sizes for AP interface This patch sets uAP BA window sizes to 64. Signed-off-by: Avinash Patil Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 0e03fe3..e0d00a7 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -48,8 +48,8 @@ #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16 #define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64 -#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48 -#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32 +#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 64 +#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 64 #define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff -- cgit v0.10.2 From 737f657f71b6e4bcb07478eb0a32eb92c80eaf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Sep 2014 18:37:26 +0200 Subject: b43: Implement PHY PLL reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should reset PLL after changing MAC frequency. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 165dbc3..3adc13f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1204,6 +1204,36 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ +void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev) +{ + struct bcma_drv_cc *bcma_cc __maybe_unused; + struct ssb_chipcommon *ssb_cc __maybe_unused; + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + bcma_cc = &dev->dev->bdev->bus->drv_cc; + + bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0); + bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); + bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4); + bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + ssb_cc = &dev->dev->sdev->bus->chipco; + + chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0); + chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4); + chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4); + chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4); + break; +#endif + } +} + #ifdef CONFIG_B43_BCMA static void b43_bcma_phy_reset(struct b43_wldev *dev) { diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 9f22e4b..c46430c 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -96,6 +96,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev); + void b43_mac_suspend(struct b43_wldev *dev); void b43_mac_enable(struct b43_wldev *dev); void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 6a0140a..bd68945 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -762,7 +762,7 @@ static void b43_phy_ht_spur_avoid(struct b43_wldev *dev, b43_mac_switch_freq(dev, spuravoid); - /* TODO: reset PLL */ + b43_wireless_core_phy_pll_reset(dev); if (spuravoid) b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX); diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index cf625d8..9f0bcf3 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -6369,7 +6369,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_mac_switch_freq(dev, spuravoid); if (dev->phy.rev == 3 || dev->phy.rev == 4) - ; /* TODO: reset PLL */ + b43_wireless_core_phy_pll_reset(dev); if (spuravoid) b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX); -- cgit v0.10.2 From 5eef40e5687da4ad0123e231e4fe952a12655f0b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 12 Sep 2014 15:50:58 -0500 Subject: rtlwifi: btcoexist: Change local debugging macros CL_*** into the standard varieties Macros CL_SNPRINTF and CL_PRINTF are always used in that order. The first formats info into a buffer, and the second dumps it with printk. As the debug system in rtlwifi has a macro that does this with a single call, it seems reasonable to use it instead. An additional benefit is that the debug level can be set when loading the driver used by the wifi device. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c index af3f604..53261d6 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -3305,7 +3305,7 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; u16 u16tmp[4]; u32 u32tmp[4]; @@ -3316,87 +3316,75 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) u8 wifi_dot11_chnl, wifi_hs_chnl; u32 fw_ver = 0, bt_patch_ver = 0; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ===========[Under Manual Control]==========="); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (!board_info->bt_exist) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); - CL_PRINTF(cli_buf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", board_info->pg_ant_num, board_info->btdm_ant_num); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", ((stack_info->profile_notified) ? "Yes" : "No"), stack_info->hci_version); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, fw_ver, bt_patch_ver, bt_patch_ver); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot11_chnl); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsMode(HsChnl)", wifi_dot11_chnl, bt_hson, wifi_hs_chnl); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", link, roam, scan); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + 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->c2h_bt_inquiry_page) ? @@ -3406,166 +3394,139 @@ void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist) ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ? "connected-idle" : "busy")))), coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", stack_info->sco_exist, stack_info->hid_exist, stack_info->pan_exist, stack_info->a2dp_exist); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); bt_info_ext = coex_sta->bt_info_ext; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", "BT Info A2DP rate", (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); - CL_PRINTF(cli_buf); for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x ", GLBtInfoSrc8192e2Ant[i], coex_sta->bt_info_c2h[i][0], coex_sta->bt_info_c2h[i][1], coex_sta->bt_info_c2h[i][2], coex_sta->bt_info_c2h[i][3]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%02x %02x %02x(%d)", coex_sta->bt_info_c2h[i][4], coex_sta->bt_info_c2h[i][5], coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); - CL_PRINTF(cli_buf); } } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "SS Type", coex_dm->cur_sstype); - CL_PRINTF(cli_buf); /* Sw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask", btcoexist->bt_info.ra_mask); - CL_PRINTF(cli_buf); /* Fw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Fw mechanism]============"); - CL_PRINTF(cli_buf); ps_tdma_case = coex_dm->cur_ps_tdma; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], ps_tdma_case, coex_dm->auto_tdma_adjust); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); - CL_PRINTF(cli_buf); /* Hw setting */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit, coex_dm->backup_ampdu_maxtime); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x778", u8tmp[0]); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x40/ 0x4f", u8tmp[0], u8tmp[1]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0xc50(dig)", u32tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", coex_sta->high_priority_rx, coex_sta->high_priority_tx); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", coex_sta->low_priority_rx, coex_sta->low_priority_tx); - CL_PRINTF(cli_buf); #if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) halbtc8192e2ant_monitor_bt_ctr(btcoexist); #endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c index e4948c8..c4acd40 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -2398,7 +2398,7 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u8tmp[4], i, bt_info_ext, pstdmacase = 0; u16 u16tmp[4]; u32 u32tmp[4]; @@ -2410,81 +2410,68 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) u8 wifi_dot11_chnl, wifi_hs_chnl; u32 fw_ver = 0, bt_patch_ver = 0; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[Under Manual Control]=========="); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (btcoexist->stop_coex_dm) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[Coex is STOPPED]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (!board_info->bt_exist) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); - CL_PRINTF(cli_buf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", board_info->pg_ant_num, board_info->btdm_ant_num, board_info->btdm_ant_pos); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", ((stack_info->profile_notified) ? "Yes" : "No"), stack_info->hci_version); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant, fw_ver, bt_patch_ver, bt_patch_ver); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot11_chnl); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", link, roam, scan); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist , BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); @@ -2493,27 +2480,25 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifi_link_status); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc", ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0), ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0), ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0), ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0), ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0)); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + 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->c2h_bt_inquiry_page) ? ("inquiry/page scan") : @@ -2524,25 +2509,22 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) coex_dm->bt_status) ? "connected-idle" : "busy")))), coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", bt_link_info->sco_exist, bt_link_info->hid_exist, bt_link_info->pan_exist, bt_link_info->a2dp_exist); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); bt_info_ext = coex_sta->bt_info_ext; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", "BT Info A2DP rate", (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate"); - CL_PRINTF(cli_buf); for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b1Ant[i], coex_sta->bt_info_c2h[i][0], @@ -2553,130 +2535,111 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) coex_sta->bt_info_c2h[i][5], coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); - CL_PRINTF(cli_buf); } } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")), btcoexist->bt_info.lps_val, btcoexist->bt_info.rpwm_val); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); if (!btcoexist->manual_control) { /* Sw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/", "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"), btcoexist->bt_info.agg_buf_size); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask", btcoexist->bt_info.ra_mask); - CL_PRINTF(cli_buf); /* Fw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Fw mechanism]============"); - CL_PRINTF(cli_buf); pstdmacase = coex_dm->cur_ps_tdma; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], pstdmacase, coex_dm->auto_tdma_adjust); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d ", "IgnWlanAct", coex_dm->cur_ignore_wlan_act); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", coex_dm->error_condition); - CL_PRINTF(cli_buf); } /* Hw setting */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit, coex_dm->backup_ampdu_max_time); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0], (u32tmp[1] & 0x3e000000) >> 25); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", ((u8tmp[0] & 0x8)>>3), u8tmp[1], ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); @@ -2694,27 +2657,23 @@ void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist) (u32tmp[3] & 0xffff); fa_cck = (u8tmp[0] << 8) + u8tmp[1]; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", u32tmp[0] & 0xffff, fa_ofdm, fa_cck); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8(coexTable)", u32tmp[0], u32tmp[1], u32tmp[2]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, coex_sta->high_priority_tx); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); - CL_PRINTF(cli_buf); #if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) halbtc8723b1ant_monitor_bt_ctr(btcoexist); #endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c index bd37d65..cefe269 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -3159,7 +3159,7 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; u32 u32tmp[4]; bool roam = false, scan = false; @@ -3171,106 +3171,91 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) u32 fw_ver = 0, bt_patch_ver = 0; u8 ap_num = 0; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ==========[Under Manual Control]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (!board_info->bt_exist) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); - CL_PRINTF(cli_buf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", board_info->pg_ant_num, board_info->btdm_ant_num); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", ((stack_info->profile_notified) ? "Yes" : "No"), stack_info->hci_version); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, fw_ver, bt_patch_ver, bt_patch_ver); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot11_chnl); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", link, roam, scan); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))), ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - CL_PRINTF(cli_buf); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", bt_link_info->sco_exist, bt_link_info->hid_exist, bt_link_info->pan_exist, bt_link_info->a2dp_exist); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); bt_info_ext = coex_sta->bt_info_ext; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", "BT Info A2DP rate", (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); - CL_PRINTF(cli_buf); for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x " "%02x %02x %02x %02x(%d)", glbt_info_src_8723b_2ant[i], @@ -3282,104 +3267,88 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) coex_sta->bt_info_c2h[i][5], coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); - CL_PRINTF(cli_buf); } } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); /* Sw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, coex_dm->limited_dig); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); - CL_PRINTF(cli_buf); /* Fw mechanism */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Fw mechanism]============"); - CL_PRINTF(cli_buf); ps_tdma_case = coex_dm->cur_ps_tdma; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], ps_tdma_case, coex_dm->auto_tdma_adjust); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); - CL_PRINTF(cli_buf); /* Hw setting */ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x880[29:25]", u8tmp[0], (u32tmp[0]&0x3e000000) >> 25); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3); - CL_PRINTF(cli_buf); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", ((u8tmp[0] & 0x8)>>3), u8tmp[1], ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); @@ -3397,29 +3366,25 @@ void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist) (u32tmp[3] & 0xffff); fa_cck = (u8tmp[0] << 8) + u8tmp[1]; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", u32tmp[0]&0xffff, fa_ofdm, fa_cck); - CL_PRINTF(cli_buf); u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, coex_sta->high_priority_tx); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); - CL_PRINTF(cli_buf); #if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) btc8723b2ant_monitor_bt_ctr(btcoexist); #endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c index 0b75e8c..b72e537 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -2235,7 +2235,7 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0; u16 u2_tmp[4]; u32 u4_tmp[4]; @@ -2246,58 +2246,49 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) u8 wifi_dot11_chnl, wifi_hs_chnl; u32 fw_ver = 0, bt_patch_ver = 0; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[Under Manual Control]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (btcoexist->stop_coex_dm) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[Coex is STOPPED]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n =========================================="); - CL_PRINTF(cli_buf); } if (!board_info->bt_exist) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); - CL_PRINTF(cli_buf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", board_info->pg_ant_num, board_info->btdm_ant_num, board_info->btdm_ant_pos); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", ((stack_info->profile_notified) ? "Yes" : "No"), stack_info->hci_version); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8821a_1ant, glcoex_ver_8821a_1ant, fw_ver, bt_patch_ver, bt_patch_ver); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); @@ -2305,33 +2296,29 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) &wifi_dot11_chnl); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", (int)wifi_rssi, (int)bt_hs_rssi); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", link, roam, scan); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); @@ -2341,7 +2328,7 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : @@ -2349,8 +2336,7 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + 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->c2h_bt_inquiry_page) ? ("inquiry/page scan") : @@ -2361,28 +2347,25 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) coex_dm->bt_status) ? "connected-idle" : "busy")))), coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", bt_link_info->sco_exist, bt_link_info->hid_exist, bt_link_info->pan_exist, bt_link_info->a2dp_exist); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); bt_info_ext = coex_sta->bt_info_ext; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", "BT Info A2DP rate", (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); - CL_PRINTF(cli_buf); for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", glbt_info_src_8821a_1ant[i], coex_sta->bt_info_c2h[i][0], @@ -2393,49 +2376,42 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) coex_sta->bt_info_c2h[i][5], coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); - CL_PRINTF(cli_buf); } } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), ((coex_sta->under_Lps ? "LPS ON" : "LPS OFF")), btcoexist->bt_info.lps_val, btcoexist->bt_info.rpwm_val); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); if (!btcoexist->manual_control) { /* Sw mechanism*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d", "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"), (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"), btcoexist->bt_info.agg_buf_size); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask", btcoexist->bt_info.ra_mask); - CL_PRINTF(cli_buf); /* Fw mechanism*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Fw mechanism]============"); - CL_PRINTF(cli_buf); ps_tdma_case = coex_dm->cur_ps_tdma; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", coex_dm->ps_tdma_para[0], @@ -2445,115 +2421,99 @@ void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist) coex_dm->ps_tdma_para[4], ps_tdma_case, coex_dm->auto_tdma_adjust); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", coex_dm->error_condition); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d ", "IgnWlanAct", coex_dm->cur_ignore_wlan_act); - CL_PRINTF(cli_buf); } /* Hw setting*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit, coex_dm->backup_ampdu_max_time); - CL_PRINTF(cli_buf); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]); - CL_PRINTF(cli_buf); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]", u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25); - CL_PRINTF(cli_buf); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x8db[6:5]", ((u1_tmp[0]&0x60)>>5)); - CL_PRINTF(cli_buf); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]", (u4_tmp[0] & 0x30000000)>>28, u4_tmp[0] & 0xff, u1_tmp[0] & 0x3); - CL_PRINTF(cli_buf); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x40/0x4c[24:23]/0x64[0]", u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1); - CL_PRINTF(cli_buf); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", u4_tmp[0], u1_tmp[0]); - CL_PRINTF(cli_buf); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0xc50(dig)", u4_tmp[0]&0xff); - CL_PRINTF(cli_buf); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d); u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]); - CL_PRINTF(cli_buf); u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", coex_sta->high_priority_rx, coex_sta->high_priority_tx); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); - CL_PRINTF(cli_buf); #if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) halbtc8821a1ant_monitor_bt_ctr(btcoexist); #endif diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c index 2322b7d..cf819f0 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -3341,7 +3341,7 @@ ex_halbtc8821a2ant_display_coex_info( { struct btc_board_info *board_info = &btcoexist->board_info; struct btc_stack_info *stack_info = &btcoexist->stack_info; - u8 *cli_buf = btcoexist->cli_buf; + struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0; u32 u4tmp[4]; bool roam = false, scan = false, link = false, wifi_under_5g = false; @@ -3351,41 +3351,35 @@ ex_halbtc8821a2ant_display_coex_info( u8 wifi_dot_11_chnl, wifi_hs_chnl; u32 fw_ver = 0, bt_patch_ver = 0; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n ============[BT Coexist info]============"); - CL_PRINTF(cli_buf); if (!board_info->bt_exist) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); - CL_PRINTF(cli_buf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!"); return; } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", board_info->pg_ant_num, board_info->btdm_ant_num); - CL_PRINTF(cli_buf); if (btcoexist->manual_control) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "[Action Manual control]!!"); - CL_PRINTF(cli_buf); } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", ((stack_info->profile_notified) ? "Yes" : "No"), stack_info->hci_version); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, fw_ver, bt_patch_ver, bt_patch_ver); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); @@ -3393,33 +3387,29 @@ ex_halbtc8821a2ant_display_coex_info( BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot_11_chnl); btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsMode(HsChnl)", wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi); - CL_PRINTF(cli_buf); 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); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan", link, roam, scan); - CL_PRINTF(cli_buf); btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); @@ -3429,7 +3419,7 @@ ex_halbtc8821a2ant_display_coex_info( BTC_GET_BL_WIFI_BUSY, &wifi_busy); btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ", "Wifi status", (wifi_under_5g ? "5G" : "2.4G"), ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" : @@ -3437,37 +3427,33 @@ ex_halbtc8821a2ant_display_coex_info( ((!wifi_busy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ? "uplink" : "downlink"))); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") : ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status) ? "connected-idle" : "busy"))), coex_sta->bt_rssi, coex_sta->bt_retry_cnt); - CL_PRINTF(cli_buf); if (stack_info->profile_notified) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", stack_info->sco_exist, stack_info->hid_exist, stack_info->pan_exist, stack_info->a2dp_exist); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); } bt_info_ext = coex_sta->bt_info_ext; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s", "BT Info A2DP rate", (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate"); - CL_PRINTF(cli_buf); for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) { if (coex_sta->bt_info_c2h_cnt[i]) { - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", glbt_info_src_8821a_2ant[i], coex_sta->bt_info_c2h[i][0], @@ -3478,139 +3464,118 @@ ex_halbtc8821a2ant_display_coex_info( coex_sta->bt_info_c2h[i][5], coex_sta->bt_info_c2h[i][6], coex_sta->bt_info_c2h_cnt[i]); - CL_PRINTF(cli_buf); } } - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")), ((coex_sta->under_lps ? "LPS ON" : "LPS OFF"))); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); /* Sw mechanism*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Sw mechanism]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig/ btLna]", coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); - CL_PRINTF(cli_buf); /* Fw mechanism*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Fw mechanism]============"); - CL_PRINTF(cli_buf); if (!btcoexist->manual_control) { ps_tdma_case = coex_dm->cur_ps_tdma; - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4], ps_tdma_case); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act); - CL_PRINTF(cli_buf); } /* Hw setting*/ - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s", "============[Hw setting]============"); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup); - CL_PRINTF(cli_buf); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x ", "0x778 (W_Act)/ 0x6cc (CoTab Sel)", u1tmp[0], u1tmp[1]); - CL_PRINTF(cli_buf); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x8db(ADC)/0xc5b[29:25](DAC)", ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1)); - CL_PRINTF(cli_buf); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28)); - CL_PRINTF(cli_buf); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x40/ 0x4c[24:23]/ 0x974", u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]); - CL_PRINTF(cli_buf); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", u4tmp[0], u1tmp[0]); - CL_PRINTF(cli_buf); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(DIG)/0xa0a(CCK-TH)", u4tmp[0], u1tmp[0]); - CL_PRINTF(cli_buf); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48); u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]); - CL_PRINTF(cli_buf); u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8", u4tmp[0], u4tmp[1], u4tmp[2]); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x770 (hi-pri Rx/Tx)", coex_sta->high_priority_rx, coex_sta->high_priority_tx); - CL_PRINTF(cli_buf); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d", "0x774(low-pri Rx/Tx)", coex_sta->low_priority_rx, coex_sta->low_priority_tx); - CL_PRINTF(cli_buf); /* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/ u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b); - CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", u1tmp[0]); - CL_PRINTF(cli_buf); btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); } diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c index 0620b22..fcf7459 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c @@ -32,7 +32,6 @@ struct btc_coexist gl_bt_coexist; u32 btc_dbg_type[BTC_MSG_MAX]; -static u8 btc_dbg_buf[100]; /*************************************************** * Debug related function @@ -652,8 +651,6 @@ bool exhalbtc_initlize_variables(struct rtl_priv *adapter) btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; - btcoexist->cli_buf = &btc_dbg_buf[0]; - btcoexist->bt_info.bt_ctrl_buf_size = false; btcoexist->bt_info.agg_buf_size = 5; diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h index bd03b8c..1345545 100644 --- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h @@ -116,9 +116,6 @@ extern u32 btc_dbg_type[]; #define WIFI_P2P_GO_CONNECTED BIT3 #define WIFI_P2P_GC_CONNECTED BIT4 -#define CL_SPRINTF snprintf -#define CL_PRINTF(buf) printk("%s", buf) - #define BTC_PRINT(dbgtype, dbgflag, printstr, ...) \ do { \ if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\ @@ -483,7 +480,6 @@ struct btc_coexist { bool initilized; bool stop_coex_dm; bool manual_control; - u8 *cli_buf; struct btc_statistics statistics; u8 pwr_mode_val[10]; -- cgit v0.10.2 From d68e9f5d8549f37332a7ec810d2864b793219845 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 13 Sep 2014 22:38:28 +0200 Subject: brcm80211: use container_of to resolve brcms_phy from brcms_phy_pub Use container_of instead of casting first structure member. Compiled but untested. Signed-off-by: Fabian Frederick Acked-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 57ecc05..941b1e4 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -128,19 +128,19 @@ static const u8 ofdm_rate_lookup[] = { void wlc_phyreg_enter(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim); } void wlc_phyreg_exit(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); } void wlc_radioreg_enter(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); udelay(10); @@ -148,7 +148,7 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih) void wlc_radioreg_exit(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); pi->phy_wreg = 0; @@ -586,7 +586,7 @@ err: void wlc_phy_detach(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (pih) { if (--pi->refcnt) @@ -613,7 +613,7 @@ bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, u16 *radioid, u16 *radiover) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); *phytype = (u16) pi->pubpi.phy_type; *phyrev = (u16) pi->pubpi.phy_rev; *radioid = pi->pubpi.radioid; @@ -624,19 +624,19 @@ wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, bool wlc_phy_get_encore(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); return pi->pubpi.abgphy_encore; } u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); return pi->pubpi.coreflags; } void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) { if (on) { @@ -673,7 +673,7 @@ void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u32 phy_bw_clkbits = 0; @@ -698,14 +698,14 @@ u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) void wlc_phy_por_inform(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->phy_init_por = true; } void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->edcrs_threshold_lock = lock; @@ -717,14 +717,14 @@ void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->do_initcal = initcal; } void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!pi || !pi->sh) return; @@ -734,7 +734,7 @@ void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!pi || !pi->sh) return; @@ -746,7 +746,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) { u32 mc; void (*phy_init)(struct brcms_phy *) = NULL; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (pi->init_in_progress) return; @@ -798,7 +798,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) void wlc_phy_cal_init(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); void (*cal_init)(struct brcms_phy *) = NULL; if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & @@ -816,7 +816,7 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih) int wlc_phy_down(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); int callbacks = 0; if (pi->phycal_timer @@ -1070,7 +1070,7 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (set) mboolset(pi->measure_hold, id); @@ -1082,7 +1082,7 @@ void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (mute) mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE); @@ -1096,7 +1096,7 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) { return; @@ -1115,7 +1115,7 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); if (ISNPHY(pi)) { @@ -1149,35 +1149,35 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->bw; } void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->bw = bw; } void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->radio_chanspec = newch; } u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->radio_chanspec; } void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 m_cur_channel; void (*chanspec_set)(struct brcms_phy *, u16) = NULL; m_cur_channel = CHSPEC_CHANNEL(chanspec); @@ -1226,7 +1226,7 @@ int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->channel_14_wide_filter = wide_filter; @@ -1246,7 +1246,7 @@ void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, struct brcms_chanvec *channels) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; uint channel; @@ -1267,7 +1267,7 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; uint channel; u16 chspec; @@ -1311,7 +1311,7 @@ u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); *qdbm = pi->tx_user_target[0]; if (override != NULL) @@ -1323,7 +1323,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr) { bool mac_enabled = false; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); memcpy(&pi->tx_user_target[TXP_FIRST_CCK], &txpwr->cck[0], BRCMS_NUM_RATES_CCK); @@ -1371,7 +1371,7 @@ void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); int i; if (qdbm > 127) @@ -1407,7 +1407,7 @@ void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, u8 *max_pwr, int txp_rate_idx) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint i; *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR; @@ -1456,7 +1456,7 @@ void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, u8 *max_txpwr, u8 *min_txpwr) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u8 tx_pwr_max = 0; u8 tx_pwr_min = 255; u8 max_num_rate; @@ -1493,14 +1493,14 @@ wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->tx_power_min; } u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->tx_power_max; } @@ -1812,21 +1812,21 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->txpwr_percent = txpwr_percent; } void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->sh->machwcap = machwcap; } void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 rxc; rxc = 0; @@ -1857,7 +1857,7 @@ void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec); @@ -1881,14 +1881,14 @@ wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->ofdm_rateset_war = war; } void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->bf_preempt_4306 = bf_preempt; } @@ -1945,7 +1945,7 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi) bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) return pi->nphy_txpwrctrl; @@ -1955,7 +1955,7 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); bool suspend; if (!pi->hwpwrctrl_capable) @@ -2038,7 +2038,7 @@ void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, uint channel) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); uint rate, num_rates; u8 min_pwr, max_pwr; @@ -2136,21 +2136,21 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); pi->antsel_type = antsel_type; } bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); return pi->phytest_on; } void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); bool suspend; pi->sh->rx_antdiv = val; @@ -2283,7 +2283,7 @@ static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi) void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u16 jssi_aux; u8 channel = 0; s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; @@ -2339,7 +2339,7 @@ void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) static void wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; bool sampling_in_progress = (pi->phynoise_state != 0); bool wait_for_intr = true; @@ -2531,7 +2531,7 @@ int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, { int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK; uint radioid = pih->radioid; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if ((pi->sh->corerev >= 11) && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) { @@ -2591,7 +2591,7 @@ void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) void wlc_phy_watchdog(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); bool delay_phy_cal = false; pi->sh->now++; @@ -2651,7 +2651,7 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih) void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); uint i; uint k; @@ -2711,7 +2711,7 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason) s16 nphy_currtemp = 0; s16 delta_temp = 0; bool do_periodic_cal = true; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); if (!ISNPHY(pi)) return; @@ -2804,7 +2804,7 @@ u8 wlc_phy_nbits(s32 value) void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->sh->hw_phytxchain = txchain; pi->sh->hw_phyrxchain = rxchain; @@ -2815,7 +2815,7 @@ void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); pi->sh->phytxchain = txchain; @@ -2827,7 +2827,7 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); *txchain = pi->sh->phytxchain; *rxchain = pi->sh->phyrxchain; @@ -2837,7 +2837,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) { s16 nphy_currtemp; u8 active_bitmap; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33; @@ -2867,7 +2867,7 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u8 siso_mcs_id, cdd_mcs_id; siso_mcs_id = @@ -2944,7 +2944,7 @@ s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); if (ISNPHY(pi)) return wlc_phy_n_txpower_ipa_ison(pi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index b2d6d6d..5f13662 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -2865,7 +2865,7 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) { bool suspend, tx_gain_override_old; struct lcnphy_txgains old_gains; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB, idleTssi0_regvalue_2C; u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); @@ -3084,7 +3084,7 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) s32 a1, b0, b1; s32 tssi, pwr, maxtargetpwr, mintargetpwr; bool suspend; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC)); @@ -4348,7 +4348,7 @@ void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi) { s8 index; u16 index2; - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 93869e8..084f18f 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -14121,7 +14121,7 @@ static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = { bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih) { - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u32 phybist0, phybist1, phybist2, phybist3, phybist4; if (NREV_GE(pi->pubpi.phy_rev, 16)) @@ -19734,7 +19734,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) u16 regval; u16 tbl_buf[16]; uint i; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); u16 tbl_opcode; bool suspend; @@ -19812,7 +19812,7 @@ void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) { u16 regval, rxen_bits; - struct brcms_phy *pi = (struct brcms_phy *) pih; + struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); regval = read_phy_reg(pi, 0xa2); rxen_bits = (regval >> 4) & 0xf; @@ -21342,7 +21342,7 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec) void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) { - struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); u16 mask = 0xfc00; u32 mc = 0; -- cgit v0.10.2 From a38a9ef1c0647f9add53ab4b43660d3fbefaa36e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 13 Sep 2014 22:38:29 +0200 Subject: brcm80211: use container_of to resolve dma_info from dma_pub Use container_of instead of casting first structure member. Compiled but untested. Signed-off-by: Fabian Frederick Acked-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 4fb9635..796f5f9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -746,7 +746,7 @@ dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring, /* !! may be called with core in reset */ void dma_detach(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -842,7 +842,7 @@ static void _dma_rxenable(struct dma_info *di) void dma_rxinit(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -924,7 +924,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) */ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff_head dma_frames; struct sk_buff *p, *next; uint len; @@ -1022,7 +1022,7 @@ static bool dma64_txidle(struct dma_info *di) */ bool dma_rxfill(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; u16 rxin, rxout; u32 flags = 0; @@ -1106,7 +1106,7 @@ bool dma_rxfill(struct dma_pub *pub) void dma_rxreclaim(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1126,7 +1126,7 @@ void dma_counterreset(struct dma_pub *pub) /* get the address of the var in order to change later */ unsigned long dma_getvar(struct dma_pub *pub, const char *name) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); if (!strcmp(name, "&txavail")) return (unsigned long)&(di->dma.txavail); @@ -1137,7 +1137,7 @@ unsigned long dma_getvar(struct dma_pub *pub, const char *name) void dma_txinit(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 control = D64_XC_XE; brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1170,7 +1170,7 @@ void dma_txinit(struct dma_pub *pub) void dma_txsuspend(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1182,7 +1182,7 @@ void dma_txsuspend(struct dma_pub *pub) void dma_txresume(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); brcms_dbg_dma(di->core, "%s:\n", di->name); @@ -1194,7 +1194,7 @@ void dma_txresume(struct dma_pub *pub) bool dma_txsuspended(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); return (di->ntxd == 0) || ((bcma_read32(di->core, @@ -1204,7 +1204,7 @@ bool dma_txsuspended(struct dma_pub *pub) void dma_txreclaim(struct dma_pub *pub, enum txd_range range) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct sk_buff *p; brcms_dbg_dma(di->core, "%s: %s\n", @@ -1225,7 +1225,7 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range) bool dma_txreset(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 status; if (di->ntxd == 0) @@ -1252,7 +1252,7 @@ bool dma_txreset(struct dma_pub *pub) bool dma_rxreset(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u32 status; if (di->nrxd == 0) @@ -1377,7 +1377,7 @@ static void dma_update_txavail(struct dma_info *di) int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, struct sk_buff *p) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; struct ieee80211_tx_info *tx_info; bool is_ampdu; @@ -1427,7 +1427,7 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, void dma_txflush(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; if (!skb_queue_empty(&session->skb_list)) @@ -1436,7 +1436,7 @@ void dma_txflush(struct dma_pub *pub) int dma_txpending(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); return ntxdactive(di, di->txin, di->txout); } @@ -1446,7 +1446,7 @@ int dma_txpending(struct dma_pub *pub) */ void dma_kick_tx(struct dma_pub *pub) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); struct brcms_ampdu_session *session = &di->ampdu_session; if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di)) @@ -1465,7 +1465,7 @@ void dma_kick_tx(struct dma_pub *pub) */ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) { - struct dma_info *di = (struct dma_info *)pub; + struct dma_info *di = container_of(pub, struct dma_info, dma); u16 start, end, i; u16 active_desc; struct sk_buff *txp; @@ -1547,7 +1547,7 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) (void *pkt, void *arg_a), void *arg_a) { - struct dma_info *di = (struct dma_info *) dmah; + struct dma_info *di = container_of(dmah, struct dma_info, dma); uint i = di->txin; uint end = di->txout; struct sk_buff *skb; -- cgit v0.10.2 From a43b5142ad7ae97a277e001cb352e509da451cb9 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 14 Sep 2014 11:14:10 +0300 Subject: fixup! wil6210: fix usage of print_hex_dump_debug Use empty inline functions instead of empty #define. Fix for "unused variable" as reported below: tree: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git master head: 167bf96dd87d2a8360cb9e9783006876dac4f579 commit: 871d8c4bbb0f23c29a21b63b1801071766f69b51 [45/62] wil6210: fix usage of print_hex_dump_debug config: i386-allyesconfig reproduce: git checkout 871d8c4bbb0f23c29a21b63b1801071766f69b51 make ARCH=i386 allyesconfig make ARCH=i386 All warnings: drivers/net/wireless/ath/wil6210/wmi.c: In function 'wmi_evt_rx_mgmt': >> drivers/net/wireless/ath/wil6210/wmi.c:341:10: warning: unused variable 'ie_len' [-Wunused-variable] size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, ^ >> drivers/net/wireless/ath/wil6210/wmi.c:340:13: warning: unused variable 'ie_buf' [-Wunused-variable] const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; ^ vim +/ie_len +341 drivers/net/wireless/ath/wil6210/wmi.c 2be7d22f Vladimir Kondratiev 2012-12-20 334 2be7d22f Vladimir Kondratiev 2012-12-20 335 if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { 2be7d22f Vladimir Kondratiev 2012-12-20 336 struct cfg80211_bss *bss; 8eea944a Vladimir Kondratiev 2014-06-16 337 u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); 8eea944a Vladimir Kondratiev 2014-06-16 338 u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); 8eea944a Vladimir Kondratiev 2014-06-16 339 u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); 8eea944a Vladimir Kondratiev 2014-06-16 340 const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; 8eea944a Vladimir Kondratiev 2014-06-16 341 size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, 8eea944a Vladimir Kondratiev 2014-06-16 342 u.beacon.variable); 8eea944a Vladimir Kondratiev 2014-06-16 343 wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); 8eea944a Vladimir Kondratiev 2014-06-16 344 wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf); :::::: The code at line 341 was first introduced by commit :::::: 8eea944af0efcdba09dac1ad220c9bfa68293279 wil6210: print more info about BSS found Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0ff0dd9..133eeb8 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -476,12 +476,19 @@ int wil_info(struct wil6210_priv *wil, const char *fmt, ...); print_hex_dump_debug("DBG[ WMI]" prefix_str,\ prefix_type, rowsize, \ groupsize, buf, len, ascii) -#else -#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) -#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) -#endif +#else /* defined(CONFIG_DYNAMIC_DEBUG) */ +static inline +void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} + +static inline +void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize, + int groupsize, const void *buf, size_t len, bool ascii) +{ +} +#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); -- cgit v0.10.2 From 5eb3645e0f35e8e12a82b055ea1204ae322d2a19 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 23:09:08 +0200 Subject: b43: tell the ucode the mac capabilities This is based on code form brcmsmac. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a980595..8ebce26ef 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -45,6 +45,7 @@ #define B43_MMIO_RAM_DATA 0x134 #define B43_MMIO_PS_STATUS 0x140 #define B43_MMIO_RADIO_HWENABLED_HI 0x158 +#define B43_MMIO_MAC_HW_CAP 0x15C /* MAC capabilities (corerev >= 13) */ #define B43_MMIO_SHM_CONTROL 0x160 #define B43_MMIO_SHM_DATA 0x164 #define B43_MMIO_SHM_DATA_UNALIGNED 0x166 @@ -253,6 +254,8 @@ enum { #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */ #define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */ +#define B43_SHM_SH_MACHW_L 0x00C0 /* Location where the ucode expects the MAC capabilities */ +#define B43_SHM_SH_MACHW_H 0x00C2 /* Location where the ucode expects the MAC capabilities */ #define B43_SHM_SH_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ /* TSSI information */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 3adc13f..85ab46c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4857,6 +4857,16 @@ static int b43_wireless_core_init(struct b43_wldev *dev) hf &= ~B43_HF_SKCFPUP; b43_hf_write(dev, hf); + /* tell the ucode MAC capabilities */ + if (dev->dev->core_rev >= 13) { + u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP); + + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L, + mac_hw_cap & 0xffff); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H, + (mac_hw_cap >> 16) & 0xffff); + } + b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, B43_DEFAULT_LONG_RETRY_LIMIT); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); -- cgit v0.10.2 From 261b758ba6203da967f0927ec31617c9f22dbdaa Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 23:09:09 +0200 Subject: b43: tell ucode the phy type and version Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 85ab46c..00d9daf 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4889,6 +4889,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); + /* write phytype and phyvers */ + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev); + if (b43_bus_host_is_pcmcia(dev->dev) || b43_bus_host_is_sdio(dev->dev)) { dev->__using_pio_transfers = true; -- cgit v0.10.2 From 30adb4d7a96d3e72447ed092e36e89ba3a6ab391 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 23:09:10 +0200 Subject: b43: add missing rate The OFDM reate 9MB was not set here Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 00d9daf..76cae315 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3151,6 +3151,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_HT: case B43_PHYTYPE_LCN: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); + b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1); -- cgit v0.10.2 From 0996c3910b8de402c319495c9560f3a909c8b866 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 23:09:11 +0200 Subject: b43: update some transmit header constants Some constants were missing and are added now. The rate mode was renamed, at least the ucode in brcsmac uses 2 for HT rates (iee80211n) and the more recent ucodes are using 3 for VHT (ieee80211ac). Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 98d9074..ba61153 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -97,9 +97,13 @@ struct b43_tx_legacy_rate_phy_ctl_entry { }; /* MAC TX control */ +#define B43_TXH_MAC_RTS_FB_SHORTPRMBL 0x80000000 /* RTS fallback preamble */ +#define B43_TXH_MAC_RTS_SHORTPRMBL 0x40000000 /* RTS main rate preamble */ +#define B43_TXH_MAC_FB_SHORTPRMBL 0x20000000 /* Main fallback preamble */ #define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */ #define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */ #define B43_TXH_MAC_KEYIDX_SHIFT 20 +#define B43_TXH_MAC_ALT_TXPWR 0x00080000 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */ #define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */ #define B43_TXH_MAC_KEYALG_SHIFT 16 #define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */ @@ -126,25 +130,25 @@ struct b43_tx_legacy_rate_phy_ctl_entry { #define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */ #define B43_TXH_EFT_FB_CCK 0x00 /* CCK */ #define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */ -#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */ -#define B43_TXH_EFT_FB_N 0x03 /* N */ +#define B43_TXH_EFT_FB_HT 0x02 /* HT */ +#define B43_TXH_EFT_FB_VHT 0x03 /* VHT */ #define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */ #define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */ #define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */ -#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */ -#define B43_TXH_EFT_RTS_N 0x0C /* N */ +#define B43_TXH_EFT_RTS_HT 0x08 /* HT */ +#define B43_TXH_EFT_RTS_VHT 0x0C /* VHT */ #define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */ #define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */ #define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */ -#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */ -#define B43_TXH_EFT_RTSFB_N 0x30 /* N */ +#define B43_TXH_EFT_RTSFB_HT 0x20 /* HT */ +#define B43_TXH_EFT_RTSFB_VHT 0x30 /* VHT */ /* PHY TX control word */ #define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */ #define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */ #define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */ -#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */ -#define B43_TXH_PHY_ENC_N 0x0003 /* N */ +#define B43_TXH_PHY_ENC_HT 0x0002 /* HT */ +#define B43_TXH_PHY_ENC_VHT 0x0003 /* VHT */ #define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ #define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */ #define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */ @@ -162,7 +166,7 @@ struct b43_tx_legacy_rate_phy_ctl_entry { #define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */ #define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */ #define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */ -#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */ +#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 40 MHz duplicate */ #define B43_TXH_PHY1_MODE 0x0038 /* Mode */ #define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */ #define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */ -- cgit v0.10.2 From 4214852ea157bdae39c2dca64f1a09aa7dbb1d00 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 23:09:12 +0200 Subject: b43: add support for setting the beacon listen interval Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 8ebce26ef..bb12586 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -300,6 +300,7 @@ enum { #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ #define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */ +#define B43_SHM_SH_BCN_LI 0x00B6 /* beacon listen interval */ /* SHM_SHARED ACK/CTS control */ #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ /* SHM_SHARED probe response variables */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 76cae315..5d4173e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3930,6 +3930,12 @@ static int b43_switch_band(struct b43_wldev *dev, return 0; } +static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval) +{ + interval = min_t(u16, interval, (u16)0xFF); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval); +} + /* Write the short and long frame retry limit values. */ static void b43_set_retry_limits(struct b43_wldev *dev, unsigned int short_retry, @@ -3958,6 +3964,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); b43_mac_suspend(dev); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) + b43_set_beacon_listen_interval(dev, conf->listen_interval); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { phy->chandef = &conf->chandef; phy->channel = conf->chandef.chan->hw_value; -- cgit v0.10.2 From a2b28601503e8d0586d207732a0e8de90e6ce05b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Sep 2014 11:25:50 +0530 Subject: ath9k: Remove unnecessary tbtt assignment The next_tbtt variable in the scheduler is needed only for GO/AP mode operation and is always read from the NEXT_TBTT_TIMER in the HW. There is no need to store the timestamp for received beacons. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 660c151..dd0f97f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -454,7 +454,7 @@ void ath9k_p2p_ps_timer(void *priv); void ath9k_chanctx_wake_queues(struct ath_softc *sc); void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); -void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev); void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, enum ath_chanctx_event ev); @@ -483,7 +483,7 @@ static inline void ath9k_offchannel_init(struct ath_softc *sc) static inline void ath9k_deinit_channel_context(struct ath_softc *sc) { } -static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, +static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev) { } diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index d2a0f12..e2712b0 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -396,7 +396,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, break; } - /* * Clear the extend_absence flag if it had been * set during the previous beacon transmission, @@ -416,6 +415,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, avp->noa_duration = 0; sc->sched.extend_absence = true; } + /* Prevent wrap-around issues */ if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30)) avp->noa_duration = 0; @@ -606,10 +606,9 @@ void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, ath_chanctx_event(sc, NULL, ev); } -void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts, +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, enum ath_chanctx_event ev) { - sc->sched.next_tbtt = ts; ath_chanctx_event(sc, NULL, ev); } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dea8e1b..0b53b74 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -909,7 +909,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, if (ath9k_is_chanctx_enabled()) { if (rx_stats->is_mybeacon) - ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp, + ath_chanctx_beacon_recv_ev(sc, ATH_CHANCTX_EVENT_BEACON_RECEIVED); } -- cgit v0.10.2 From 7f30eac9938daf12e34334c8eb1f8fba37fc7ace Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Sep 2014 11:25:51 +0530 Subject: ath9k: Check beaconing mode properly In MCC mode, the TSF of a context needs to be adjusted only if it is GO/AP. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index e2712b0..77c99eb5 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -260,6 +260,9 @@ static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) cur = sc->cur_chan; prev = ath_chanctx_get_next(sc, cur); + if (!prev->switch_after_beacon) + return; + getrawmonotonic(&ts); cur_tsf = (u32) cur->tsf_val + ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); -- cgit v0.10.2 From 4ee26de18d267170fe44ecb6cc4bafaa218b26e3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Sep 2014 11:25:52 +0530 Subject: ath9k: Set offchannel state properly When switching offchannel, BSS related information in the HW has to be reset to default values. Add a routine to do this. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a556c29..9e921d1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -953,21 +953,6 @@ void ath9k_calculate_iter_data(struct ath_softc *sc, list_for_each_entry(avp, &ctx->vifs, list) ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); - -#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT - if (ctx == &sc->offchannel.chan) { - struct ieee80211_vif *vif; - - if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) - vif = sc->offchannel.scan_vif; - else - vif = sc->offchannel.roc_vif; - - if (vif) - ath9k_vif_iter(iter_data, vif->addr, vif); - iter_data->beacons = false; - } -#endif } static void ath9k_set_assoc_state(struct ath_softc *sc, @@ -1007,6 +992,43 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, vif->addr, common->curbssid); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +static void ath9k_set_offchannel_state(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_vif *vif = NULL; + + ath9k_ps_wakeup(sc); + + if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) + vif = sc->offchannel.scan_vif; + else + vif = sc->offchannel.roc_vif; + + if (WARN_ON(!vif)) + goto exit; + + eth_zero_addr(common->curbssid); + eth_broadcast_addr(common->bssidmask); + ether_addr_copy(common->macaddr, vif->addr); + common->curaid = 0; + ah->opmode = vif->type; + ah->imask &= ~ATH9K_INT_SWBA; + ah->imask &= ~ATH9K_INT_TSFOOR; + ah->slottime = ATH9K_SLOT_TIME_9; + + ath_hw_setbssidmask(common); + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(sc->sc_ah); + ath9k_hw_set_interrupts(ah); + ath9k_hw_init_global_settings(ah); + +exit: + ath9k_ps_restore(sc); +} +#endif + /* Called with sc->mutex held. */ void ath9k_calculate_summary_state(struct ath_softc *sc, struct ath_chanctx *ctx) @@ -1021,6 +1043,11 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, if (ctx != sc->cur_chan) return; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + if (ctx == &sc->offchannel.chan) + return ath9k_set_offchannel_state(sc); +#endif + ath9k_ps_wakeup(sc); ath9k_calculate_iter_data(sc, ctx, &iter_data); -- cgit v0.10.2 From af87dd33a17151f46ae50a564a799f9ea9397539 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Sep 2014 11:25:53 +0530 Subject: ath9k: Remove useless opmode check The opmode is verified to be NL80211_IFTYPE_STATION before calling ath9k_set_assoc_state(). Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9e921d1..dffefff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -963,13 +963,6 @@ static void ath9k_set_assoc_state(struct ath_softc *sc, unsigned long flags; set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - /* Set the AID, BSSID and do beacon-sync only when - * the HW opmode is STATION. - * - * But the primary bit is set above in any case. - */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - return; ether_addr_copy(common->curbssid, bss_conf->bssid); common->curaid = bss_conf->aid; -- cgit v0.10.2 From 1030f9fe65602465a89beaa05c3343cf9fd68a88 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Sep 2014 11:25:54 +0530 Subject: ath9k: Fix primary station configuration Assign 'primary_sta' to the active primary station interface after iterating over the list of interfaces. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dffefff..6083359 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1088,9 +1088,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, iter_data.beacons = true; ath9k_set_assoc_state(sc, iter_data.primary_sta, changed); - if (!ctx->primary_sta || - !ctx->primary_sta->bss_conf.assoc) - ctx->primary_sta = iter_data.primary_sta; + ctx->primary_sta = iter_data.primary_sta; } else { ctx->primary_sta = NULL; memset(common->curbssid, 0, ETH_ALEN); @@ -1119,8 +1117,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, else clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - ctx->primary_sta = iter_data.primary_sta; - ath9k_ps_restore(sc); } -- cgit v0.10.2 From 8e15e09465977d38ed4cc45af10148a4e6542f1c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:07 +0200 Subject: ath9k: export methods related to ACK timeout estimation Remove static keyword and export ath9k_hw_setslottime(), ath9k_hw_set_ack_timeout() and ath9k_hw_set_cts_timeout() in hw.h. These methods will be used in ACK timeout estimation algorithm (dynack) Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ef5f5a6..ce395e2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -935,21 +935,21 @@ static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us) REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val); } -static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) 0xFFFF); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); } -static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); } -static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 51b4ebe..f36d971 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1080,6 +1080,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us); + #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { -- cgit v0.10.2 From 36678b2b67d7d455d5f4054604f97834a316a121 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:08 +0200 Subject: ath9k: add duration field to ath_tx_status Add duration field to ath_tx_status in order to report frame duration for each entry in multi-retry chain. These fields will be used in ACK timeout estimation algorithm (dynack) Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 59af9f9..669cb37 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -381,6 +381,13 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->evm1 = ads->AR_TxEVM1; ts->evm2 = ads->AR_TxEVM2; + status = ACCESS_ONCE(ads->ds_ctl4); + ts->duration[0] = MS(status, AR_PacketDur0); + ts->duration[1] = MS(status, AR_PacketDur1); + status = ACCESS_ONCE(ads->ds_ctl5); + ts->duration[2] = MS(status, AR_PacketDur2); + ts->duration[3] = MS(status, AR_PacketDur3); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 71e38e8..e5f7c11 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -355,9 +355,11 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { struct ar9003_txs *ads; + struct ar9003_txc *adc; u32 status; ads = &ah->ts_ring[ah->ts_tail]; + adc = (struct ar9003_txc *)ads; status = ACCESS_ONCE(ads->status8); if ((status & AR_TxDone) == 0) @@ -426,6 +428,13 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); + status = ACCESS_ONCE(adc->ctl15); + ts->duration[0] = MS(status, AR_PacketDur0); + ts->duration[1] = MS(status, AR_PacketDur1); + status = ACCESS_ONCE(adc->ctl16); + ts->duration[2] = MS(status, AR_PacketDur2); + ts->duration[3] = MS(status, AR_PacketDur3); + memset(ads, 0, sizeof(*ads)); return 0; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 6c56caf..cd05a77 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -121,6 +121,7 @@ struct ath_tx_status { u32 evm0; u32 evm1; u32 evm2; + u32 duration[4]; }; struct ath_rx_status { -- cgit v0.10.2 From c774d57fd47c71675bb8c41a4dc2aafd78baa39d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:09 +0200 Subject: ath9k: add dynamic ACK timeout estimation Add dynamic ACK timeout estimation algorithm based on ACK frame RX timestamp, TX frame timestamp and frame duration. Signed-off-by: Lorenzo Bianconi Tested-by: Philippe Duchein Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index c1a4ade..a3b6e27 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -234,6 +234,7 @@ void ath_printk(const char *level, const struct ath_common *common, * AR9462. * @ATH_DBG_DFS: radar datection * @ATH_DBG_WOW: Wake on Wireless + * @ATH_DBG_DYNACK: dynack handling * @ATH_DBG_ANY: enable all debugging * * The debug level is used to control the amount and type of debugging output @@ -262,6 +263,7 @@ enum ATH_DEBUG { ATH_DBG_DFS = 0x00010000, ATH_DBG_WOW = 0x00020000, ATH_DBG_CHAN_CTX = 0x00040000, + ATH_DBG_DYNACK = 0x00080000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index dd0f97f..8cd116e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -274,6 +274,9 @@ struct ath_node { struct ath_rx_rate_stats rx_rate_stats; #endif u8 key_idx[4]; + + u32 ackto; + struct list_head list; }; struct ath_tx_control { diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c new file mode 100644 index 0000000..6ae8e0b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" +#include "hw.h" +#include "dynack.h" + +#define COMPUTE_TO (5 * HZ) +#define LATEACK_DELAY (10 * HZ) +#define LATEACK_TO 256 +#define MAX_DELAY 300 +#define EWMA_LEVEL 96 +#define EWMA_DIV 128 + +/** + * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation + * + */ +static inline u32 ath_dynack_ewma(u32 old, u32 new) +{ + return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV; +} + +/** + * ath_dynack_get_sifs - get sifs time based on phy used + * @ah: ath hw + * @phy: phy used + * + */ +static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy) +{ + u32 sifs = CCK_SIFS_TIME; + + if (phy == WLAN_RC_PHY_OFDM) { + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_QUARTER; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_HALF; + else + sifs = OFDM_SIFS_TIME; + } + return sifs; +} + +/** + * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask + * @ah: ath hw + * @mac: receiver address + */ +static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) +{ + int i; + struct ath_common *common = ath9k_hw_common(ah); + + for (i = 0; i < ETH_ALEN; i++) { + if ((common->macaddr[i] & common->bssidmask[i]) != + (mac[i] & common->bssidmask[i])) + return false; + } + + return true; +} + +/** + * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_ackto(struct ath_hw *ah) +{ + struct ath_node *an; + u32 to = 0; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + + list_for_each_entry(an, &da->nodes, list) + if (an->ackto > to) + to = an->ackto; + + if (to && da->ackto != to) { + u32 slottime; + + slottime = (to - 3) / 2; + da->ackto = to; + ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n", + da->ackto, slottime); + ath9k_hw_setslottime(ah, slottime); + ath9k_hw_set_ack_timeout(ah, da->ackto); + ath9k_hw_set_cts_timeout(ah, da->ackto); + } +} + +/** + * ath_dynack_compute_to - compute STA ACK timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_to(struct ath_hw *ah) +{ + u32 ackto, ack_ts; + u8 *dst, *src; + struct ieee80211_sta *sta; + struct ath_node *an; + struct ts_info *st_ts; + struct ath_dynack *da = &ah->dynack; + + rcu_read_lock(); + + while (da->st_rbf.h_rb != da->st_rbf.t_rb && + da->ack_rbf.h_rb != da->ack_rbf.t_rb) { + ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb]; + st_ts = &da->st_rbf.ts[da->st_rbf.h_rb]; + dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest; + src = da->st_rbf.addr[da->st_rbf.h_rb].h_src; + + ath_dbg(ath9k_hw_common(ah), DYNACK, + "ack_ts %u st_ts %u st_dur %u [%u-%u]\n", + ack_ts, st_ts->tstamp, st_ts->dur, + da->ack_rbf.h_rb, da->st_rbf.h_rb); + + if (ack_ts > st_ts->tstamp + st_ts->dur) { + ackto = ack_ts - st_ts->tstamp - st_ts->dur; + + if (ackto < MAX_DELAY) { + sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst, + src); + if (sta) { + an = (struct ath_node *)sta->drv_priv; + an->ackto = ath_dynack_ewma(an->ackto, + ackto); + ath_dbg(ath9k_hw_common(ah), DYNACK, + "%pM to %u\n", dst, an->ackto); + if (time_is_before_jiffies(da->lto)) { + ath_dynack_compute_ackto(ah); + da->lto = jiffies + COMPUTE_TO; + } + } + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + } else { + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + } + + rcu_read_unlock(); +} + +/** + * ath_dynack_sample_tx_ts - status timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: tx status info + * + */ +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts) +{ + u8 ridx; + struct ieee80211_hdr *hdr; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled) + return; + + spin_lock_bh(&da->qlock); + + hdr = (struct ieee80211_hdr *)skb->data; + + /* late ACK */ + if (ts->ts_status & ATH9K_TXERR_XRETRY) { + if (ieee80211_is_assoc_req(hdr->frame_control) || + ieee80211_is_assoc_resp(hdr->frame_control)) { + ath_dbg(common, DYNACK, "late ack\n"); + ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2); + ath9k_hw_set_ack_timeout(ah, LATEACK_TO); + ath9k_hw_set_cts_timeout(ah, LATEACK_TO); + da->lto = jiffies + LATEACK_DELAY; + } + + spin_unlock_bh(&da->qlock); + return; + } + + ridx = ts->ts_rateindex; + + da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; + da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration[ts->ts_rateindex]; + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1); + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2); + + if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { + u32 phy, sifs; + const struct ieee80211_rate *rate; + struct ieee80211_tx_rate *rates = info->status.rates; + + rate = &common->sbands[info->band].bitrates[rates[ridx].idx]; + if (info->band == IEEE80211_BAND_2GHZ && + !(rate->flags & IEEE80211_RATE_ERP_G)) + phy = WLAN_RC_PHY_CCK; + else + phy = WLAN_RC_PHY_OFDM; + + sifs = ath_dynack_get_sifs(ah, phy); + da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs; + } + + ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n", + hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp, + da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb, + (da->st_rbf.t_rb + 1) % ATH_DYN_BUF); + + INCR(da->st_rbf.t_rb, ATH_DYN_BUF); + if (da->st_rbf.t_rb == da->st_rbf.h_rb) + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_tx_ts); + +/** + * ath_dynack_sample_ack_ts - ACK timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: rx timestamp + * + */ +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, + u32 ts) +{ + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled) + return; + + spin_lock_bh(&da->qlock); + da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts; + + ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n", + da->ack_rbf.tstamp[da->ack_rbf.t_rb], + da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF); + + INCR(da->ack_rbf.t_rb, ATH_DYN_BUF); + if (da->ack_rbf.t_rb == da->ack_rbf.h_rb) + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_ack_ts); + +/** + * ath_dynack_node_init - init ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) +{ + /* ackto = slottime + sifs + air delay */ + u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + struct ath_dynack *da = &ah->dynack; + + an->ackto = ackto; + + spin_lock(&da->qlock); + list_add_tail(&an->list, &da->nodes); + spin_unlock(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_init); + +/** + * ath_dynack_node_deinit - deinit ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) +{ + struct ath_dynack *da = &ah->dynack; + + spin_lock(&da->qlock); + list_del(&an->list); + spin_unlock(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_deinit); + +/** + * ath_dynack_reset - reset dynack processing + * @ah: ath hw + * + */ +void ath_dynack_reset(struct ath_hw *ah) +{ + /* ackto = slottime + sifs + air delay */ + u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64; + struct ath_dynack *da = &ah->dynack; + + da->lto = jiffies; + da->ackto = ackto; + + da->st_rbf.t_rb = 0; + da->st_rbf.h_rb = 0; + da->ack_rbf.t_rb = 0; + da->ack_rbf.h_rb = 0; + + /* init acktimeout */ + ath9k_hw_setslottime(ah, (ackto - 3) / 2); + ath9k_hw_set_ack_timeout(ah, ackto); + ath9k_hw_set_cts_timeout(ah, ackto); +} +EXPORT_SYMBOL(ath_dynack_reset); + +/** + * ath_dynack_init - init dynack data structure + * @ah: ath hw + * + */ +void ath_dynack_init(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + + memset(da, 0, sizeof(struct ath_dynack)); + + spin_lock_init(&da->qlock); + INIT_LIST_HEAD(&da->nodes); + + ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION; +} diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h new file mode 100644 index 0000000..6d7bef9 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DYNACK_H +#define DYNACK_H + +#define ATH_DYN_BUF 64 + +struct ath_hw; +struct ath_node; + +/** + * struct ath_dyn_rxbuf - ACK frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @tstamp: ACK RX timestamp buffer + */ +struct ath_dyn_rxbuf { + u16 h_rb, t_rb; + u32 tstamp[ATH_DYN_BUF]; +}; + +struct ts_info { + u32 tstamp; + u32 dur; +}; + +struct haddr_pair { + u8 h_dest[ETH_ALEN]; + u8 h_src[ETH_ALEN]; +}; + +/** + * struct ath_dyn_txbuf - tx frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @addr: dest/src address pair for a given TX frame + * @ts: TX frame timestamp buffer + */ +struct ath_dyn_txbuf { + u16 h_rb, t_rb; + struct haddr_pair addr[ATH_DYN_BUF]; + struct ts_info ts[ATH_DYN_BUF]; +}; + +/** + * struct ath_dynack - dynack processing info + * @enabled: enable dyn ack processing + * @ackto: current ACK timeout + * @lto: last ACK timeout computation + * @nodes: ath_node linked list + * @qlock: ts queue spinlock + * @ack_rbf: ACK ts ring buffer + * @st_rbf: status ts ring buffer + */ +struct ath_dynack { + bool enabled; + int ackto; + unsigned long lto; + + struct list_head nodes; + + /* protect timestamp queue access */ + spinlock_t qlock; + struct ath_dyn_rxbuf ack_rbf; + struct ath_dyn_txbuf st_rbf; +}; + +#if defined(CONFIG_ATH9K_DYNACK) +void ath_dynack_reset(struct ath_hw *ah); +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_init(struct ath_hw *ah); +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts); +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts); +#else +static inline void ath_dynack_init(struct ath_hw *ah) {} +static inline void ath_dynack_node_init(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_node_deinit(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah, + struct sk_buff *skb, u32 ts) {} +static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah, + struct sk_buff *skb, + struct ath_tx_status *ts) {} +#endif + +#endif /* DYNACK_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ce395e2..e71f824 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -647,6 +647,8 @@ int ath9k_hw_init(struct ath_hw *ah) return ret; } + ath_dynack_init(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_init); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f36d971..b9eef33 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -29,6 +29,7 @@ #include "reg.h" #include "phy.h" #include "btcoex.h" +#include "dynack.h" #include "../regd.h" @@ -924,6 +925,8 @@ struct ath_hw { int (*external_reset)(void); const struct firmware *eeprom_blob; + + struct ath_dynack dynack; }; struct ath_bus_ops { -- cgit v0.10.2 From ce7191526854f79b90bf627c5a8b8993491a3c2b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:10 +0200 Subject: ath9k: add config for (en|dis)abling ACK timeout estimation Add ACK timeout estimation algorithm to ath9k Makefile and Kconfig Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index b8f570e..896e632 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -92,6 +92,15 @@ config ATH9K_DFS_CERTIFIED developed. At this point enabling this option won't do anything except increase code size. +config ATH9K_DYNACK + bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)" + depends on ATH9K + default n + ---help--- + This option enables ath9k dynamic ACK timeout estimation algorithm + based on ACK frame RX timestamp, TX frame timestamp and frame + duration + config ATH9K_TX99 bool "Atheros ath9k TX99 testing support" depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 6b4020a..73704c1 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -49,6 +49,9 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ar9003_mci.o + +ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o + obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -- cgit v0.10.2 From 7aefa8aacbd4694db9a7ea7cbff490a1e31c3613 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:11 +0200 Subject: ath9k: do not overwrite ACK timeout estimation Do not overwrite ACK timeout estimation in ath9k_hw_init_global_settings() if dynack processing has been enabled Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e71f824..949d5d6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1055,6 +1055,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ctstimeout += 48 - sifstime - ah->slottime; } + if (ah->dynack.enabled) { + acktimeout = ah->dynack.ackto; + ctstimeout = acktimeout; + slottime = (acktimeout - 3) / 2; + } else { + ah->dynack.ackto = acktimeout; + } + ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); -- cgit v0.10.2 From 982e0395d32780f6b3fcdbced1d17bbe909dd19f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:12 +0200 Subject: ath9k: add sampling methods for (tx|rx) timestamp Add sampling methods for ACK RX timestamp in ath_rx_tasklet() and for TX frame timestamp in ath_tx_complete_aggr() and in ath_tx_process_buffer(). These samples will be used in dynack processing for ACK timeout estimation Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 0b53b74..66c5fe8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1007,6 +1007,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unsigned long flags; dma_addr_t new_buf_addr; unsigned int budget = 512; + struct ieee80211_hdr *hdr; if (edma) dma_type = DMA_BIDIRECTIONAL; @@ -1136,6 +1137,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath9k_apply_ampdu_details(sc, &rs, rxs); ath_debug_rate_stats(sc, &rs, skb); + hdr = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_ack(hdr->frame_control)) + ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp); + ieee80211_rx(hw, skb); requeue_drop_frag: diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2819866..93ad31b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -587,6 +587,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memcpy(tx_info->control.rates, rates, sizeof(rates)); ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); rc_update = false; + if (bf == bf->bf_lastbf) + ath_dynack_sample_tx_ts(sc->sc_ah, + bf->bf_mpdu, + ts); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, @@ -687,6 +691,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, memcpy(info->control.rates, bf->rates, sizeof(info->control.rates)); ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); + ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts); } ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); } else -- cgit v0.10.2 From 35c273eafe764791c635a45b5292039bbffea38f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:13 +0200 Subject: ath9k: enable control frame reception Set control frame bit in rx filter if dynack processing has been activated in order to enable ACK frame reception Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 66c5fe8..42108f0 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -400,7 +400,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; - if (sc->cur_chan->rxfilter & FIF_CONTROL) + if ((sc->cur_chan->rxfilter & FIF_CONTROL) || + sc->sc_ah->dynack.enabled) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && -- cgit v0.10.2 From 7a90744c333e5038793217f695dbbdb776b58698 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:14 +0200 Subject: ath9k: add debugfs support for dynack Add ack_to entry to debugfs in order to dump current ACK timeout value Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 5d8b5ea..46f20a3 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1169,6 +1169,29 @@ static const struct file_operations fops_btcoex = { }; #endif +#ifdef CONFIG_ATH9K_DYNACK +static ssize_t read_file_ackto(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; + + len = sprintf(buf, "%u %c\n", ah->dynack.ackto, + (ah->dynack.enabled) ? 'A' : 'S'); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_ackto = { + .read = read_file_ackto, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; +#endif + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1374,5 +1397,10 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_btcoex); #endif +#ifdef CONFIG_ATH9K_DYNACK + debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_ackto); +#endif + return 0; } -- cgit v0.10.2 From 24a1936bda0aa1ccf95c63dd3042a970885aaf11 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:15 +0200 Subject: ath9k: enable dynack using set_coverage_class codepath Enable ACK timeout estimation algorithm if set_coverage_class routine has been called with negative coverage_class parameter. Dynack is automatically disabled setting valid value for coverage class Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6083359..6969aba 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1876,6 +1876,20 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +static void ath9k_enable_dynack(struct ath_softc *sc) +{ +#ifdef CONFIG_ATH9K_DYNACK + u32 rfilt; + struct ath_hw *ah = sc->sc_ah; + + ath_dynack_reset(ah); + + ah->dynack.enabled = true; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); +#endif +} + static void ath9k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { @@ -1886,11 +1900,22 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, return; mutex_lock(&sc->mutex); - ah->coverage_class = coverage_class; - ath9k_ps_wakeup(sc); - ath9k_hw_init_global_settings(ah); - ath9k_ps_restore(sc); + if (coverage_class >= 0) { + ah->coverage_class = coverage_class; + if (ah->dynack.enabled) { + u32 rfilt; + + ah->dynack.enabled = false; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); + } + ath9k_ps_wakeup(sc); + ath9k_hw_init_global_settings(ah); + ath9k_ps_restore(sc); + } else if (!ah->dynack.enabled) { + ath9k_enable_dynack(sc); + } mutex_unlock(&sc->mutex); } -- cgit v0.10.2 From 44b47a7d483297f753577ed23369fcdeb67aac5e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 02:13:16 +0200 Subject: ath9k: initialize ath_node linked list Initialize neighbor linked list used by dynack to compute ACK timeout as the maximum STA ACK timeout Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6969aba..3e485f7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -345,12 +345,16 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, memset(&an->key_idx, 0, sizeof(an->key_idx)); ath_tx_node_init(sc, an); + + ath_dynack_node_init(sc->sc_ah, an); } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_tx_node_cleanup(sc, an); + + ath_dynack_node_deinit(sc->sc_ah, an); } void ath9k_tasklet(unsigned long data) -- cgit v0.10.2 From 853854d6b2e43b7f7fbbcc87558503f00aa0abf2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 16 Sep 2014 07:19:27 +0530 Subject: ath9k: Fix build error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This happens when CONFIG_ATH9K_CHANNEL_CONTEXT is not enabled. ../drivers/net/wireless/ath/ath9k/recv.c: In function ‘ath_rx_ps_beacon’: ../drivers/net/wireless/ath/ath9k/recv.c:553:27: error: ‘struct ath_softc’ has no member named ‘offchannel’ if (sc->cur_chan == &sc->offchannel.chan) ^ ../scripts/Makefile.build:257: recipe for target 'drivers/net/wireless/ath/ath9k/recv.o' failed make[10]: *** [drivers/net/wireless/ath/ath9k/recv.o] Error 1 ../scripts/Makefile.build:404: recipe for target 'drivers/net/wireless/ath/ath9k' failed make[9]: *** [drivers/net/wireless/ath/ath9k] Error 2 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 42108f0..6914e21 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -550,10 +550,12 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT if (ath9k_is_chanctx_enabled()) { if (sc->cur_chan == &sc->offchannel.chan) skip_beacon = true; } +#endif if (!skip_beacon && !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) -- cgit v0.10.2 From 7a0a260a0f6ff0226c33cf28a5cc26711ab0ae5f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 16 Sep 2014 16:43:42 +0200 Subject: ath9k: enable ext channel pulse detection Enable pulse detection on extension channel if 40MHz channel width has been set Signed-off-by: Lorenzo Bianconi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 949d5d6..3aed729 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1966,6 +1966,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->hw->conf.radar_enabled) { /* set HW specific DFS configuration */ + ah->radar_conf.ext_channel = IS_CHAN_HT40(chan); ath9k_hw_set_radar_params(ah); } -- cgit v0.10.2