summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2014-09-22 09:39:20 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-09-26 17:22:27 -0400
commitf7953b2ad66cc5fc66e13d5c0a40e61b45cdfca8 (patch)
tree42ed50f3a91fd5844c57762113212e1fccb2b720
parent38506ecefab911785d5e1aa5889f6eeb462e0954 (diff)
rtlwifi: Modify core.c for new drivers
Each of the routines in the rtlwifi common driver needs to be modified for the coming changes. This patch prepares core.c, but also touches other files. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rtlwifi/base.c8
-rw-r--r--drivers/net/wireless/rtlwifi/base.h8
-rw-r--r--drivers/net/wireless/rtlwifi/core.c744
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h76
4 files changed, 602 insertions, 234 deletions
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 3b599b6ffbdf..8234cdb03b11 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -1128,8 +1128,8 @@ EXPORT_SYMBOL_GPL(rtl_is_special_data);
* functions called by core.c
*
*********************************************************/
-int rtl_tx_agg_start(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_tid_data *tid_data;
@@ -1158,8 +1158,8 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw,
return 0;
}
-int rtl_tx_agg_stop(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u16 tid)
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 0cd07420777a..eaa511041640 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -120,10 +120,10 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
void rtl_watch_dog_timer_callback(unsigned long data);
-int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- u16 tid, u16 *ssn);
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- u16 tid);
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid);
int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 98e564d61a0e..dea754aecdaf 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -11,10 +11,6 @@
* 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 LICENSE.
*
@@ -31,10 +27,12 @@
#include "core.h"
#include "cam.h"
#include "base.h"
-#include "pci.h"
#include "ps.h"
+#include "btcoexist/rtl_btc.h"
+#include <linux/firmware.h>
#include <linux/export.h>
+#include <net/cfg80211.h>
void rtl_addr_delay(u32 addr)
{
@@ -103,7 +101,7 @@ void rtl_fw_cb(const struct firmware *firmware, void *context)
int err;
RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
- "Firmware callback routine entered!\n");
+ "Firmware callback routine entered!\n");
complete(&rtlpriv->firmware_loading_complete);
if (!firmware) {
if (rtlpriv->cfg->alt_fw_name) {
@@ -135,7 +133,7 @@ EXPORT_SYMBOL(rtl_fw_cb);
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
- int err;
+ int err = 0;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -157,28 +155,33 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool support_remote_wakeup = false;
if (is_hal_stop(rtlhal))
return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+ (u8 *)(&support_remote_wakeup));
/* here is must, because adhoc do stop and start,
* but stop with RFOFF may cause something wrong,
* like adhoc TP
*/
- if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
+ if (unlikely(ppsc->rfpwr_state == ERFOFF))
rtl_ips_nic_on(hw);
- }
mutex_lock(&rtlpriv->locks.conf_mutex);
+ /* if wowlan supported, DON'T clear connected info */
+ if (!(support_remote_wakeup &&
+ rtlhal->enter_pnp_sleep)) {
+ mac->link_state = MAC80211_NOLINK;
+ memset(mac->bssid, 0, 6);
+ mac->vendor = PEER_UNKNOWN;
- mac->link_state = MAC80211_NOLINK;
- memset(mac->bssid, 0, ETH_ALEN);
- mac->vendor = PEER_UNKNOWN;
-
- /*reset sec info */
- rtl_cam_reset_sec_info(hw);
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
- rtl_deinit_deferred_work(hw);
+ rtl_deinit_deferred_work(hw);
+ }
rtlpriv->intf_ops->adapter_stop(hw);
mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -202,7 +205,6 @@ static void rtl_op_tx(struct ieee80211_hw *hw,
if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb))
rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc);
-
return;
err_free:
@@ -216,18 +218,17 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
int err = 0;
- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
-
if (mac->vif) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"vif has been set!! mac->vif = 0x%p\n", mac->vif);
return -EOPNOTSUPP;
}
+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
-
switch (ieee80211_vif_type_p2p(vif)) {
case NL80211_IFTYPE_P2P_CLIENT:
mac->p2p = P2P_ROLE_CLIENT;
@@ -238,10 +239,8 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
"NL80211_IFTYPE_STATION\n");
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
- rtlpriv->cfg->maps
- [RTL_IBSS_INT_MASKS]);
+ rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
}
- mac->link_state = MAC80211_LINKED;
break;
case NL80211_IFTYPE_ADHOC:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -254,7 +253,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
else
mac->basic_rates = 0xff0;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
- (u8 *) (&mac->basic_rates));
+ (u8 *)(&mac->basic_rates));
break;
case NL80211_IFTYPE_P2P_GO:
@@ -271,7 +270,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
else
mac->basic_rates = 0xff0;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
- (u8 *) (&mac->basic_rates));
+ (u8 *)(&mac->basic_rates));
break;
case NL80211_IFTYPE_MESH_POINT:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -288,7 +287,7 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "operation mode %d is not supported!\n", vif->type);
+ "operation mode %d is not support!\n", vif->type);
err = -EOPNOTSUPP;
goto out;
}
@@ -326,8 +325,7 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
if (mac->beacon_enabled == 1) {
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
- rtlpriv->cfg->maps
- [RTL_IBSS_INT_MASKS]);
+ rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
}
}
@@ -342,12 +340,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mac->vendor = PEER_UNKNOWN;
mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
-
static int rtl_op_change_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum nl80211_iftype new_type, bool p2p)
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type, bool p2p)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
int ret;
@@ -357,10 +355,221 @@ static int rtl_op_change_interface(struct ieee80211_hw *hw,
vif->p2p = p2p;
ret = rtl_op_add_interface(hw, vif);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- "p2p %x\n", p2p);
+ "p2p %x\n", p2p);
return ret;
}
+#ifdef CONFIG_PM
+static u16 crc16_ccitt(u8 data, u16 crc)
+{
+ u8 shift_in, data_bit, crc_bit11, crc_bit4, crc_bit15;
+ u8 i;
+ u16 result;
+
+ for (i = 0; i < 8; i++) {
+ crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
+ data_bit = (data & (BIT(0) << i) ? 1 : 0);
+ shift_in = crc_bit15 ^ data_bit;
+
+ result = crc << 1;
+ if (shift_in == 0)
+ result &= (~BIT(0));
+ else
+ result |= BIT(0);
+
+ crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
+ if (crc_bit11 == 0)
+ result &= (~BIT(12));
+ else
+ result |= BIT(12);
+
+ crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
+ if (crc_bit4 == 0)
+ result &= (~BIT(5));
+ else
+ result |= BIT(5);
+
+ crc = result;
+ }
+
+ return crc;
+}
+
+static u16 _calculate_wol_pattern_crc(u8 *pattern, u16 len)
+{
+ u16 crc = 0xffff;
+ u32 i;
+
+ for (i = 0; i < len; i++)
+ crc = crc16_ccitt(pattern[i], crc);
+
+ crc = ~crc;
+
+ return crc;
+}
+
+static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wow)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = &rtlpriv->mac80211;
+ struct cfg80211_pkt_pattern *patterns = wow->patterns;
+ struct rtl_wow_pattern rtl_pattern;
+ const u8 *pattern_os, *mask_os;
+ u8 mask[MAX_WOL_BIT_MASK_SIZE] = {0};
+ u8 content[MAX_WOL_PATTERN_SIZE] = {0};
+ u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 multicast_addr1[2] = {0x33, 0x33};
+ u8 multicast_addr2[3] = {0x01, 0x00, 0x5e};
+ u8 i, mask_len;
+ u16 j, len;
+
+ for (i = 0; i < wow->n_patterns; i++) {
+ memset(&rtl_pattern, 0, sizeof(struct rtl_wow_pattern));
+ memset(mask, 0, MAX_WOL_BIT_MASK_SIZE);
+ if (patterns[i].pattern_len > MAX_WOL_PATTERN_SIZE) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_WARNING,
+ "Pattern[%d] is too long\n", i);
+ continue;
+ }
+ pattern_os = patterns[i].pattern;
+ mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
+ mask_os = patterns[i].mask;
+ RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+ "pattern content\n", pattern_os,
+ patterns[i].pattern_len);
+ RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+ "mask content\n", mask_os, mask_len);
+ /* 1. unicast? multicast? or broadcast? */
+ if (memcmp(pattern_os, broadcast_addr, 6) == 0)
+ rtl_pattern.type = BROADCAST_PATTERN;
+ else if (memcmp(pattern_os, multicast_addr1, 2) == 0 ||
+ memcmp(pattern_os, multicast_addr2, 3) == 0)
+ rtl_pattern.type = MULTICAST_PATTERN;
+ else if (memcmp(pattern_os, mac->mac_addr, 6) == 0)
+ rtl_pattern.type = UNICAST_PATTERN;
+ else
+ rtl_pattern.type = UNKNOWN_TYPE;
+
+ /* 2. translate mask_from_os to mask_for_hw */
+
+/******************************************************************************
+ * pattern from OS uses 'ethenet frame', like this:
+
+ | 6 | 6 | 2 | 20 | Variable | 4 |
+ |--------+--------+------+-----------+------------+-----|
+ | 802.3 Mac Header | IP Header | TCP Packet | FCS |
+ | DA | SA | Type |
+
+ * BUT, packet catched by our HW is in '802.11 frame', begin from LLC,
+
+ | 24 or 30 | 6 | 2 | 20 | Variable | 4 |
+ |-------------------+--------+------+-----------+------------+-----|
+ | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS |
+ | Others | Tpye |
+
+ * Therefore, we need translate mask_from_OS to mask_to_hw.
+ * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
+ * because new mask[0~5] means 'SA', but our HW packet begins from LLC,
+ * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
+ ******************************************************************************/
+
+ /* Shift 6 bits */
+ for (j = 0; j < mask_len - 1; j++) {
+ mask[j] = mask_os[j] >> 6;
+ mask[j] |= (mask_os[j + 1] & 0x3F) << 2;
+ }
+ mask[j] = (mask_os[j] >> 6) & 0x3F;
+ /* Set bit 0-5 to zero */
+ mask[0] &= 0xC0;
+
+ RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+ "mask to hw\n", mask, mask_len);
+ for (j = 0; j < (MAX_WOL_BIT_MASK_SIZE + 1) / 4; j++) {
+ rtl_pattern.mask[j] = mask[j * 4];
+ rtl_pattern.mask[j] |= (mask[j * 4 + 1] << 8);
+ rtl_pattern.mask[j] |= (mask[j * 4 + 2] << 16);
+ rtl_pattern.mask[j] |= (mask[j * 4 + 3] << 24);
+ }
+
+ /* To get the wake up pattern from the mask.
+ * We do not count first 12 bits which means
+ * DA[6] and SA[6] in the pattern to match HW design.
+ */
+ len = 0;
+ for (j = 12; j < patterns[i].pattern_len; j++) {
+ if ((mask_os[j / 8] >> (j % 8)) & 0x01) {
+ content[len] = pattern_os[j];
+ len++;
+ }
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+ "pattern to hw\n", content, len);
+ /* 3. calculate crc */
+ rtl_pattern.crc = _calculate_wol_pattern_crc(content, len);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ "CRC_Remainder = 0x%x", rtl_pattern.crc);
+
+ /* 4. write crc & mask_for_hw to hw */
+ rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i);
+ }
+ rtl_write_byte(rtlpriv, 0x698, wow->n_patterns);
+}
+
+static int rtl_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wow)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct timeval ts;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n");
+ if (WARN_ON(!wow))
+ return -EINVAL;
+
+ /* to resolve s4 can not wake up*/
+ do_gettimeofday(&ts);
+ rtlhal->last_suspend_sec = ts.tv_sec;
+
+ if ((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) && wow->n_patterns)
+ _rtl_add_wowlan_patterns(hw, wow);
+
+ rtlhal->driver_is_goingto_unload = true;
+ rtlhal->enter_pnp_sleep = true;
+
+ rtl_lps_leave(hw);
+ rtl_op_stop(hw);
+ device_set_wakeup_enable(wiphy_dev(hw->wiphy), true);
+ return 0;
+}
+
+static int rtl_op_resume(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct timeval ts;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n");
+ rtlhal->driver_is_goingto_unload = false;
+ rtlhal->enter_pnp_sleep = false;
+ rtlhal->wake_from_pnp_sleep = true;
+
+ /* to resovle s4 can not wake up*/
+ do_gettimeofday(&ts);
+ if (ts.tv_sec - rtlhal->last_suspend_sec < 5)
+ return -1;
+
+ rtl_op_start(hw);
+ device_set_wakeup_enable(wiphy_dev(hw->wiphy), false);
+ ieee80211_resume_disconnect(mac->vif);
+ rtlhal->wake_from_pnp_sleep = false;
+ return 0;
+}
+#endif
+
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -373,7 +582,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
return 1;
mutex_lock(&rtlpriv->locks.conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/
+ if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /* BIT(2)*/
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n");
}
@@ -408,8 +617,8 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
* is worked very well */
if (!rtlpriv->psc.multi_buffered)
queue_delayed_work(rtlpriv->works.rtl_wq,
- &rtlpriv->works.ps_work,
- MSECS(5));
+ &rtlpriv->works.ps_work,
+ MSECS(5));
} else {
rtl_swlps_rf_awake(hw);
rtlpriv->psc.sw_ps_enabled = false;
@@ -423,20 +632,26 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
mac->retry_long = hw->conf.long_frame_max_tx_count;
mac->retry_short = hw->conf.long_frame_max_tx_count;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
- (u8 *) (&hw->conf.
- long_frame_max_tx_count));
+ (u8 *)(&hw->conf.long_frame_max_tx_count));
}
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
+ !rtlpriv->proximity.proxim_on) {
struct ieee80211_channel *channel = hw->conf.chandef.chan;
+ enum nl80211_chan_width width = hw->conf.chandef.width;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u8 wide_chan = (u8) channel->hw_value;
+ /* channel_type is for 20&40M */
+ if (width < NL80211_CHAN_WIDTH_80)
+ channel_type =
+ cfg80211_get_chandef_type(&hw->conf.chandef);
if (mac->act_scanning)
mac->n_channels++;
if (rtlpriv->dm.supp_phymode_switch &&
- mac->link_state < MAC80211_LINKED &&
- !mac->act_scanning) {
+ mac->link_state < MAC80211_LINKED &&
+ !mac->act_scanning) {
if (rtlpriv->cfg->ops->chk_switch_dmdp)
rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
@@ -450,48 +665,98 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
*info for cisco1253 bw20, so we modify
*it here based on UPPER & LOWER
*/
- switch (cfg80211_get_chandef_type(&hw->conf.chandef)) {
- case NL80211_CHAN_HT20:
- case NL80211_CHAN_NO_HT:
- /* SC */
- mac->cur_40_prime_sc =
- PRIME_CHNL_OFFSET_DONT_CARE;
- rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20;
- mac->bw_40 = false;
- break;
- case NL80211_CHAN_HT40MINUS:
- /* SC */
- mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER;
- rtlphy->current_chan_bw =
- HT_CHANNEL_WIDTH_20_40;
- mac->bw_40 = true;
-
- /*wide channel */
- wide_chan -= 2;
-
- break;
- case NL80211_CHAN_HT40PLUS:
- /* SC */
- mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER;
- rtlphy->current_chan_bw =
- HT_CHANNEL_WIDTH_20_40;
- mac->bw_40 = true;
-
- /*wide channel */
- wide_chan += 2;
-
- break;
- default:
- mac->bw_40 = false;
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "switch case not processed\n");
- break;
+
+ if (width >= NL80211_CHAN_WIDTH_80) {
+ if (width == NL80211_CHAN_WIDTH_80) {
+ u32 center = hw->conf.chandef.center_freq1;
+ u32 primary =
+ (u32)hw->conf.chandef.chan->center_freq;
+
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_80;
+ mac->bw_80 = true;
+ mac->bw_40 = true;
+ if (center > primary) {
+ mac->cur_80_prime_sc =
+ PRIME_CHNL_OFFSET_LOWER;
+ if (center - primary == 10) {
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_UPPER;
+
+ wide_chan += 2;
+ } else if (center - primary == 30) {
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_LOWER;
+
+ wide_chan += 6;
+ }
+ } else {
+ mac->cur_80_prime_sc =
+ PRIME_CHNL_OFFSET_UPPER;
+ if (primary - center == 10) {
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_LOWER;
+
+ wide_chan -= 2;
+ } else if (primary - center == 30) {
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_UPPER;
+
+ wide_chan -= 6;
+ }
+ }
+ }
+ } else {
+ switch (channel_type) {
+ case NL80211_CHAN_HT20:
+ case NL80211_CHAN_NO_HT:
+ /* SC */
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_DONT_CARE;
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_20;
+ mac->bw_40 = false;
+ mac->bw_80 = false;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ /* SC */
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_UPPER;
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_20_40;
+ mac->bw_40 = true;
+ mac->bw_80 = false;
+
+ /*wide channel */
+ wide_chan -= 2;
+
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ /* SC */
+ mac->cur_40_prime_sc =
+ PRIME_CHNL_OFFSET_LOWER;
+ rtlphy->current_chan_bw =
+ HT_CHANNEL_WIDTH_20_40;
+ mac->bw_40 = true;
+ mac->bw_80 = false;
+
+ /*wide channel */
+ wide_chan += 2;
+
+ break;
+ default:
+ mac->bw_40 = false;
+ mac->bw_80 = false;
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
}
if (wide_chan <= 0)
wide_chan = 1;
- /* In scanning, before we go offchannel we may send a ps = 1
+ /* In scanning, when before we offchannel we may send a ps=1
* null to AP, and then we may send a ps = 0 null to AP quickly,
* but first null may have caused AP to put lots of packet to
* hw tx buffer. These packets must be tx'd before we go off
@@ -503,12 +768,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
rtlpriv->mac80211.offchan_delay = false;
mdelay(50);
}
+
rtlphy->current_channel = wide_chan;
rtlpriv->cfg->ops->switch_channel(hw);
rtlpriv->cfg->ops->set_channel_access(hw);
- rtlpriv->cfg->ops->set_bw_mode(hw,
- cfg80211_get_chandef_type(&hw->conf.chandef));
+ rtlpriv->cfg->ops->set_bw_mode(hw, channel_type);
}
mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -517,45 +782,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
}
static void rtl_op_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *new_flags, u64 multicast)
+ unsigned int changed_flags,
+ unsigned int *new_flags, u64 multicast)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u32 rx_conf;
*new_flags &= RTL_SUPPORTED_FILTERS;
- if (!changed_flags)
+ if (0 == changed_flags)
return;
- /* if ssid not set to hw don't check bssid
- * here just used for linked scanning, & linked
- * and nolink check bssid is set in set network_type */
- if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
- (mac->link_state >= MAC80211_LINKED)) {
- if (mac->opmode != NL80211_IFTYPE_AP &&
- mac->opmode != NL80211_IFTYPE_MESH_POINT) {
- if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
- rtlpriv->cfg->ops->set_chk_bssid(hw, false);
- } else {
- rtlpriv->cfg->ops->set_chk_bssid(hw, true);
- }
- }
- }
-
- /* must be called after set_chk_bssid since that function modifies the
- * RCR register too. */
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
-
/*TODO: we disable broadcase now, so enable here */
if (changed_flags & FIF_ALLMULTI) {
if (*new_flags & FIF_ALLMULTI) {
- rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
rtlpriv->cfg->maps[MAC_RCR_AB];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive multicast frame\n");
} else {
- rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+ mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
rtlpriv->cfg->maps[MAC_RCR_AB]);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive multicast frame\n");
@@ -564,43 +809,55 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & FIF_FCSFAIL) {
if (*new_flags & FIF_FCSFAIL) {
- rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Enable receive FCS error frame\n");
} else {
- rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"Disable receive FCS error frame\n");
}
}
+ /* if ssid not set to hw don't check bssid
+ * here just used for linked scanning, & linked
+ * and nolink check bssid is set in set network_type
+ */
+ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+ (mac->link_state >= MAC80211_LINKED)) {
+ if (mac->opmode != NL80211_IFTYPE_AP &&
+ mac->opmode != NL80211_IFTYPE_MESH_POINT) {
+ if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+ rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+ else
+ rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+ }
+ }
if (changed_flags & FIF_CONTROL) {
if (*new_flags & FIF_CONTROL) {
- rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- "Enable receive control frame\n");
+ "Enable receive control frame.\n");
} else {
- rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- "Disable receive control frame\n");
+ "Disable receive control frame.\n");
}
}
if (changed_flags & FIF_OTHER_BSS) {
if (*new_flags & FIF_OTHER_BSS) {
- rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+ mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- "Enable receive other BSS's frame\n");
+ "Enable receive other BSS's frame.\n");
} else {
- rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+ mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- "Disable receive other BSS's frame\n");
+ "Disable receive other BSS's frame.\n");
}
}
-
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
}
static int rtl_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -612,7 +869,7 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
struct rtl_sta_info *sta_entry;
if (sta) {
- sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
spin_lock_bh(&rtlpriv->locks.entry_list_lock);
list_add_tail(&sta_entry->list, &rtlpriv->entry_list);
spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
@@ -620,15 +877,17 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
sta_entry->wireless_mode = WIRELESS_MODE_G;
if (sta->supp_rates[0] <= 0xf)
sta_entry->wireless_mode = WIRELESS_MODE_B;
- if (sta->ht_cap.ht_supported == true)
+ if (sta->ht_cap.ht_supported)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
if (vif->type == NL80211_IFTYPE_ADHOC)
sta_entry->wireless_mode = WIRELESS_MODE_G;
} else if (rtlhal->current_bandtype == BAND_ON_5G) {
sta_entry->wireless_mode = WIRELESS_MODE_A;
- if (sta->ht_cap.ht_supported == true)
- sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+ if (sta->ht_cap.ht_supported)
+ sta_entry->wireless_mode = WIRELESS_MODE_N_5G;
+ if (sta->vht_cap.vht_supported)
+ sta_entry->wireless_mode = WIRELESS_MODE_AC_5G;
if (vif->type == NL80211_IFTYPE_ADHOC)
sta_entry->wireless_mode = WIRELESS_MODE_A;
@@ -639,9 +898,10 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
- "Add sta addr is %pM\n", sta->addr);
+ "Add sta addr is %pM\n", sta->addr);
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
}
+
return 0;
}
@@ -654,17 +914,15 @@ static int rtl_op_sta_remove(struct ieee80211_hw *hw,
if (sta) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"Remove sta addr is %pM\n", sta->addr);
- sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
sta_entry->wireless_mode = 0;
sta_entry->ratr_index = 0;
-
spin_lock_bh(&rtlpriv->locks.entry_list_lock);
list_del(&sta_entry->list);
spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
}
return 0;
}
-
static int _rtl_get_hal_qnum(u16 queue)
{
int qnum;
@@ -694,8 +952,8 @@ static int _rtl_get_hal_qnum(u16 queue)
*for rtl819x BE = 0, BK = 1, VI = 2, VO = 3
*/
static int rtl_op_conf_tx(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, u16 queue,
- const struct ieee80211_tx_queue_params *param)
+ struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *param)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -718,14 +976,14 @@ static int rtl_op_conf_tx(struct ieee80211_hw *hw,
}
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf, u32 changed)
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- struct ieee80211_sta *sta = NULL;
mutex_lock(&rtlpriv->locks.conf_mutex);
if ((vif->type == NL80211_IFTYPE_ADHOC) ||
@@ -743,15 +1001,14 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->beacon_enabled = 1;
rtlpriv->cfg->ops->update_interrupt_mask(hw,
rtlpriv->cfg->maps
- [RTL_IBSS_INT_MASKS],
- 0);
+ [RTL_IBSS_INT_MASKS], 0);
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
}
}
if ((changed & BSS_CHANGED_BEACON_ENABLED &&
- !bss_conf->enable_beacon)) {
+ !bss_conf->enable_beacon)) {
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"ADHOC DISABLE BEACON\n");
@@ -772,8 +1029,12 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
/*TODO: reference to enum ieee80211_bss_change */
if (changed & BSS_CHANGED_ASSOC) {
+ u8 mstatus;
if (bss_conf->assoc) {
struct ieee80211_sta *sta = NULL;
+ u8 keep_alive = 10;
+
+ mstatus = RT_MEDIA_CONNECT;
/* we should reset all sec info & cam
* before set cam after linked, we should not
* reset in disassoc, that will cause tkip->wep
@@ -791,47 +1052,89 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
+
rcu_read_lock();
sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
if (!sta) {
- pr_err("ieee80211_find_sta returned NULL\n");
rcu_read_unlock();
goto out;
}
-
- if (vif->type == NL80211_IFTYPE_STATION && sta)
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
RT_TRACE(rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD,
"send PS STATIC frame\n");
if (rtlpriv->dm.supp_phymode_switch) {
if (sta->ht_cap.ht_supported)
rtl_send_smps_action(hw, sta,
- IEEE80211_SMPS_STATIC);
+ IEEE80211_SMPS_STATIC);
}
+
+ if (rtlhal->current_bandtype == BAND_ON_5G) {
+ mac->mode = WIRELESS_MODE_A;
+ } else {
+ if (sta->supp_rates[0] <= 0xf)
+ mac->mode = WIRELESS_MODE_B;
+ else
+ mac->mode = WIRELESS_MODE_G;
+ }
+
+ if (sta->ht_cap.ht_supported) {
+ if (rtlhal->current_bandtype == BAND_ON_2_4G)
+ mac->mode = WIRELESS_MODE_N_24G;
+ else
+ mac->mode = WIRELESS_MODE_N_5G;
+ }
+
+ if (sta->vht_cap.vht_supported) {
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ mac->mode = WIRELESS_MODE_AC_5G;
+ else
+ mac->mode = WIRELESS_MODE_AC_24G;
+ }
+
+ if (vif->type == NL80211_IFTYPE_STATION && sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
rcu_read_unlock();
+ /* to avoid AP Disassociation caused by inactivity */
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_KEEP_ALIVE,
+ (u8 *)(&keep_alive));
+
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_ASSOC\n");
} else {
+ mstatus = RT_MEDIA_DISCONNECT;
+
if (mac->link_state == MAC80211_LINKED) {
rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work);
}
-
if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, ETH_ALEN);
mac->vendor = PEER_UNKNOWN;
+ mac->mode = 0;
if (rtlpriv->dm.supp_phymode_switch) {
if (rtlpriv->cfg->ops->chk_switch_dmdp)
rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
-
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_UN_ASSOC\n");
}
+ rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+ /* For FW LPS:
+ * To tell firmware we have connected or disconnected
+ */
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_JOINBSSRPT,
+ (u8 *)(&mstatus));
+ ppsc->report_linked = (mstatus == RT_MEDIA_CONNECT) ?
+ true : false;
+
+ if (rtlpriv->cfg->ops->get_btc_status())
+ rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify(
+ rtlpriv, mstatus);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -843,11 +1146,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n",
- bss_conf->use_short_preamble);
+ bss_conf->use_short_preamble);
mac->short_preamble = bss_conf->use_short_preamble;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
- &mac->short_preamble);
+ (u8 *)(&mac->short_preamble));
}
if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -860,13 +1163,17 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->slot_time = RTL_SLOT_TIME_20;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
- &mac->slot_time);
+ (u8 *)(&mac->slot_time));
}
if (changed & BSS_CHANGED_HT) {
- RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_HT\n");
+ struct ieee80211_sta *sta = NULL;
+
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+ "BSS_CHANGED_HT\n");
+
rcu_read_lock();
- sta = get_sta(hw, vif, bss_conf->bssid);
+ sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
if (sta) {
if (sta->ht_cap.ampdu_density >
mac->current_ampdu_density)
@@ -880,7 +1187,7 @@ static void rtl_op_bss_info_changed(struct ieee802