Commit 26634c4b authored by Larry Finger's avatar Larry Finger Committed by John W. Linville

rtlwifi Modify existing bits to match vendor version 2013.02.07

These changes add the new variables for P2P and modify the various struct
definitions for other new features.

This patch updates files base.{c,h} for the changes in the newest vendor
driver.

This patch updates files ps.{c,h} for the changes in the newest vendor
driver.

This patch updates files debug.{c,h}, efuse.c, pci.{c,h}, and wifi.h for
the changes in the newest vendor driver.

This patch updates files core.c, ps.c, rc.c, and wifi.h for
the changes in the newest vendor driver.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: jcheung@suse.com
Cc: machen@suse.com
Cc: mmarek@suse.cz
Cc: zhiyuan_yang@realsil.com.cn
Cc: page_he@realsil.com.cn
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent cbafb601
......@@ -54,7 +54,8 @@
*5) frame process functions
*6) IOT functions
*7) sysfs functions
*8) ...
*8) vif functions
*9) ...
*/
/*********************************************************
......@@ -198,34 +199,46 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
/*
*hw->wiphy->bands[IEEE80211_BAND_2GHZ]
/*hw->wiphy->bands[IEEE80211_BAND_2GHZ]
*base on ant_num
*rx_mask: RX mask
*if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7
*if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15
*if rx_ant >=3 rx_mask[2]=0xff;
*if BW_40 rx_mask[4]=0x01;
*if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
*if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
*if rx_ant >= 3 rx_mask[2]= 0xff;
*if BW_40 rx_mask[4]= 0x01;
*highest supported RX rate
*/
if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) {
if (rtlpriv->dm.supp_phymode_switch) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T2R or 2T2R\n");
RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
"Support phy mode switch\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0xFF;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
} else if (get_rf_type(rtlphy) == RF_1T1R) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0x00;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
} else {
if (get_rf_type(rtlphy) == RF_1T2R ||
get_rf_type(rtlphy) == RF_2T2R) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"1T2R or 2T2R\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0xFF;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest =
cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
} else if (get_rf_type(rtlphy) == RF_1T1R) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0x00;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest =
cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
}
}
}
......@@ -311,6 +324,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_CONNECTION_MONITOR |
/* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
/* swlps or hwlps has been set in diff chip in init_sw_vars */
......@@ -323,8 +338,12 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->rts_threshold = 2347;
hw->queues = AC_MAX;
......@@ -354,9 +373,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
/* <1> timer */
init_timer(&rtlpriv->works.watchdog_timer);
setup_timer(&rtlpriv->works.watchdog_timer,
rtl_watch_dog_timer_callback, (unsigned long)hw);
setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw);
/* <2> work queue */
rtlpriv->works.hw = hw;
......@@ -369,6 +389,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
(void *)rtl_swlps_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
(void *)rtl_swlps_rfon_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
(void *)rtl_fwevt_wq_callback);
}
......@@ -382,6 +404,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
cancel_delayed_work(&rtlpriv->works.ps_work);
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
cancel_delayed_work(&rtlpriv->works.fwevt_wq);
}
void rtl_init_rfkill(struct ieee80211_hw *hw)
......@@ -436,12 +459,6 @@ int rtl_init_core(struct ieee80211_hw *hw)
if (rtl_regd_init(hw, rtl_reg_notifier)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "REGD init failed\n");
return 1;
} else {
/* CRDA regd hint must after init CRDA */
if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"regulatory_hint fail\n");
}
}
/* <4> locks */
......@@ -449,15 +466,24 @@ int rtl_init_core(struct ieee80211_hw *hw)
mutex_init(&rtlpriv->locks.ps_mutex);
spin_lock_init(&rtlpriv->locks.ips_lock);
spin_lock_init(&rtlpriv->locks.irq_th_lock);
spin_lock_init(&rtlpriv->locks.irq_pci_lock);
spin_lock_init(&rtlpriv->locks.tx_lock);
spin_lock_init(&rtlpriv->locks.h2c_lock);
spin_lock_init(&rtlpriv->locks.rf_ps_lock);
spin_lock_init(&rtlpriv->locks.rf_lock);
spin_lock_init(&rtlpriv->locks.waitq_lock);
spin_lock_init(&rtlpriv->locks.entry_list_lock);
spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
spin_lock_init(&rtlpriv->locks.fw_ps_lock);
spin_lock_init(&rtlpriv->locks.lps_lock);
/* <5> init list */
INIT_LIST_HEAD(&rtlpriv->entry_list);
rtlmac->link_state = MAC80211_NOLINK;
/* <5> init deferred work */
/* <6> init deferred work */
_rtl_init_deferred_work(hw);
return 0;
......@@ -523,7 +549,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw,
if (mac->opmode == NL80211_IFTYPE_STATION)
bw_40 = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC)
mac->opmode == NL80211_IFTYPE_ADHOC ||
mac->opmode == NL80211_IFTYPE_MESH_POINT)
bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
if (bw_40 && sgi_40)
......@@ -578,23 +605,26 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
if (mac->opmode == NL80211_IFTYPE_STATION) {
tcb_desc->ratr_index = 0;
} else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
} else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (tcb_desc->multicast || tcb_desc->broadcast) {
tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
tcb_desc->use_driver_rate = 1;
tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
} else {
/* TODO */
tcb_desc->ratr_index = ratr_index;
}
tcb_desc->ratr_index = ratr_index;
} else if (mac->opmode == NL80211_IFTYPE_AP) {
tcb_desc->ratr_index = ratr_index;
}
}
if (rtlpriv->dm.useramask) {
/* TODO we will differentiate adhoc and station futrue */
if (mac->opmode == NL80211_IFTYPE_STATION) {
tcb_desc->ratr_index = ratr_index;
/* TODO we will differentiate adhoc and station future */
if (mac->opmode == NL80211_IFTYPE_STATION ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
tcb_desc->mac_id = 0;
if (mac->mode == WIRELESS_MODE_N_24G)
......@@ -608,7 +638,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
else if (mac->mode & WIRELESS_MODE_A)
tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
} else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC) {
mac->opmode == NL80211_IFTYPE_ADHOC) {
if (NULL != sta) {
if (sta->aid > 0)
tcb_desc->mac_id = sta->aid + 1;
......@@ -619,7 +649,6 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
}
}
}
}
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
......@@ -633,7 +662,8 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
if (!sta)
return;
if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC) {
mac->opmode == NL80211_IFTYPE_ADHOC ||
mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
return;
} else if (mac->opmode == NL80211_IFTYPE_STATION) {
......@@ -834,8 +864,8 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
if (rtlpriv->dm.supp_phymode_switch &&
mac->link_state < MAC80211_LINKED &&
(ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
if (rtlpriv->cfg->ops->check_switch_to_dmdp)
rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
if (rtlpriv->cfg->ops->chk_switch_dmdp)
rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
......@@ -924,6 +954,56 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(rtl_get_tcb_desc);
static bool addbareq_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_sta *sta = NULL;
struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
struct rtl_sta_info *sta_entry = NULL;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
u16 capab = 0, tid = 0;
struct rtl_tid_data *tid_data;
struct sk_buff *skb_delba = NULL;
struct ieee80211_rx_status rx_status = { 0 };
rcu_read_lock();
sta = rtl_find_sta(hw, hdr->addr3);
if (sta == NULL) {
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_EMERG,
"sta is NULL\n");
rcu_read_unlock();
return true;
}
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
if (!sta_entry) {
rcu_read_unlock();
return true;
}
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
tid_data = &sta_entry->tids[tid];
if (tid_data->agg.rx_agg_state == RTL_RX_AGG_START) {
skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
if (skb_delba) {
rx_status.freq = hw->conf.channel->center_freq;
rx_status.band = hw->conf.channel->band;
rx_status.flag |= RX_FLAG_DECRYPTED;
rx_status.flag |= RX_FLAG_MACTIME_END;
rx_status.rate_idx = 0;
rx_status.signal = 50 + 10;
memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status,
sizeof(rx_status));
RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
"fake del\n", skb_delba->data,
skb_delba->len);
ieee80211_rx_irqsafe(hw, skb_delba);
}
}
rcu_read_unlock();
return false;
}
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
......@@ -948,6 +1028,11 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
"%s ACT_ADDBAREQ From :%pM\n",
is_tx ? "Tx" : "Rx", hdr->addr2);
RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
skb->data, skb->len);
if (!is_tx)
if (addbareq_rx(hw, skb))
return true;
break;
case ACT_ADDBARSP:
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
......@@ -1101,6 +1186,58 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw,
return 0;
}
int rtl_rx_agg_start(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_tid_data *tid_data;
struct rtl_sta_info *sta_entry = NULL;
if (sta == NULL)
return -EINVAL;
if (unlikely(tid >= MAX_TID_COUNT))
return -EINVAL;
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
if (!sta_entry)
return -ENXIO;
tid_data = &sta_entry->tids[tid];
RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG,
"on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
tid_data->seq_number);
tid_data->agg.rx_agg_state = RTL_RX_AGG_START;
return 0;
}
int rtl_rx_agg_stop(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_sta_info *sta_entry = NULL;
if (sta == NULL)
return -EINVAL;
if (!sta->addr) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
return -EINVAL;
}
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
"on ra = %pM tid = %d\n", sta->addr, tid);
if (unlikely(tid >= MAX_TID_COUNT))
return -EINVAL;
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP;
return 0;
}
int rtl_tx_agg_oper(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid)
{
......@@ -1132,6 +1269,34 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw,
* wq & timer callback functions
*
*********************************************************/
/* this function is used for roaming */
void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
return;
if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
return;
/* check if this really is a beacon */
if (!ieee80211_is_beacon(hdr->frame_control) &&
!ieee80211_is_probe_resp(hdr->frame_control))
return;
/* min. beacon length + FCS_LEN */
if (skb->len <= 40 + FCS_LEN)
return;
/* and only beacons from the associated BSSID, please */
if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
return;
rtlpriv->link_info.bcn_rx_inperiod++;
}
void rtl_watchdog_wq_callback(void *data)
{
struct rtl_works *rtlworks = container_of_dwork_rtl(data,
......@@ -1142,6 +1307,8 @@ void rtl_watchdog_wq_callback(void *data)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
bool busytraffic = false;
bool tx_busy_traffic = false;
bool rx_busy_traffic = false;
bool higher_busytraffic = false;
bool higher_busyrxtraffic = false;
u8 idx, tid;
......@@ -1191,8 +1358,13 @@ void rtl_watchdog_wq_callback(void *data)
aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
/* (2) check traffic busy */
if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) {
busytraffic = true;
if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod)
rx_busy_traffic = true;
else
tx_busy_traffic = false;
}
/* Higher Tx/Rx data. */
if (aver_rx_cnt_inperiod > 4000 ||
......@@ -1236,7 +1408,7 @@ void rtl_watchdog_wq_callback(void *data)
if (enter_ps)
rtl_lps_enter(hw);
else
rtl_lps_leave(hw);
schedule_work(&rtlpriv->works.lps_leave_work);
}
rtlpriv->link_info.num_rx_inperiod = 0;
......@@ -1246,10 +1418,37 @@ void rtl_watchdog_wq_callback(void *data)
rtlpriv->link_info.busytraffic = busytraffic;
rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
rtlpriv->link_info.rx_busy_traffic = rx_busy_traffic;
rtlpriv->link_info.tx_busy_traffic = tx_busy_traffic;
rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
/* <3> DM */
rtlpriv->cfg->ops->dm_watchdog(hw);
/* <4> roaming */
if (mac->link_state == MAC80211_LINKED &&
mac->opmode == NL80211_IFTYPE_STATION) {
if ((rtlpriv->link_info.bcn_rx_inperiod +
rtlpriv->link_info.num_rx_inperiod) == 0) {
rtlpriv->link_info.roam_times++;
RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"AP off for %d s\n",
(rtlpriv->link_info.roam_times * 2));
/* if we can't recv beacon for 6s, we should
* reconnect this AP
*/
if (rtlpriv->link_info.roam_times >= 3) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"AP off, try to reconnect now\n");
rtlpriv->link_info.roam_times = 0;
ieee80211_connection_loss(rtlpriv->mac80211.vif);
}
} else {
rtlpriv->link_info.roam_times = 0;
}
}
rtlpriv->link_info.bcn_rx_inperiod = 0;
}
void rtl_watch_dog_timer_callback(unsigned long data)
......@@ -1264,6 +1463,28 @@ void rtl_watch_dog_timer_callback(unsigned long data)
jiffies + MSECS(RTL_WATCH_DOG_TIME));
}
void rtl_fwevt_wq_callback(void *data)
{
struct rtl_works *rtlworks =
container_of_dwork_rtl(data, struct rtl_works, fwevt_wq);
struct ieee80211_hw *hw = rtlworks->hw;
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->cfg->ops->c2h_command_handle(hw);
}
void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
{
struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
if (buddy_priv == NULL)
return;
rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
}
/*********************************************************
*
* frame process functions
......@@ -1334,14 +1555,16 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
}
int rtl_send_smps_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 *da, u8 *bssid,
struct ieee80211_sta *sta,
enum ieee80211_smps_mode smps)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
struct sk_buff *skb = NULL;
struct rtl_tcb_desc tcb_desc;
u8 bssid[ETH_ALEN] = {0};
memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (rtlpriv->mac80211.act_scanning)
......@@ -1356,21 +1579,67 @@ int rtl_send_smps_action(struct ieee80211_hw *hw,
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP)
memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN);
else
memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN);
skb = rtl_make_smps_action(hw, smps, sta->addr, bssid);
/* this is a type = mgmt * stype = action frame */
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl_sta_info *sta_entry =
(struct rtl_sta_info *) sta->drv_priv;
sta_entry->mimo_ps = smps;
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
info->control.rates[0].idx = 0;
info->band = hw->conf.channel->band;
rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
}
return 1;
err_free:
return 0;
}
EXPORT_SYMBOL(rtl_send_smps_action);
/* There seem to be issues in mac80211 regarding when del ba frames can be
* received. As a work around, we make a fake del_ba if we receive a ba_req;
* however, rx_agg was opened to let mac80211 release some ba related
* resources. This del_ba is for tx only.
*/
struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
u8 *sa, u8 *bssid, u16 tid)
{
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
struct sk_buff *skb;
struct ieee80211_mgmt *action_frame;
u16 params;
/* 27 = header + category + action + smps mode */
skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
if (!skb)
return NULL;
skb_reserve(skb, hw->extra_tx_headroom);
action_frame = (void *)skb_put(skb, 34);
memset(action_frame, 0, 34);
memcpy(action_frame->sa, sa, ETH_ALEN);
memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN);
memcpy(action_frame->bssid, bssid, ETH_ALEN);
action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
action_frame->u.action.category = WLAN_CATEGORY_BACK;
action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
params = (u16)(1 << 11); /* bit 11 initiator */
params |= (u16)(tid << 12); /* bit 15:12 TID number */
action_frame->u.action.u.delba.params = cpu_to_le16(params);
action_frame->u.action.u.delba.reason_code =
cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
return skb;
}
/*********************************************************
*
......@@ -1587,11 +1856,17 @@ MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
struct rtl_global_var global_var = {};
static int __init rtl_core_module_init(void)
{
if (rtl_rate_control_register())
pr_err("Unable to register rtl_rc, use default RC !!\n");
/* init some global vars */
INIT_LIST_HEAD(&global_var.glb_priv_list);
spin_lock_init(&global_var.glb_list_lock);
return 0;
}
......
......@@ -113,6 +113,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw);
void rtl_init_rfkill(struct ieee80211_hw *hw);
void rtl_deinit_rfkill(struct ieee80211_hw *hw);
void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
void rtl_watch_dog_timer_callback(unsigned long data);
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
......@@ -126,7 +127,12 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, 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,
u16 tid);
int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
void rtl_watchdog_wq_callback(void *data);
void rtl_fwevt_wq_callback(void *data);
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
......@@ -134,14 +140,18 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
int rtl_send_smps_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 *da, u8 *bssid,
enum ieee80211_smps_mode smps);
struct ieee80211_sta *sta,
enum ieee80211_smps_mode smps);
u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl_tid_to_ac(u8 tid);
extern struct attribute_group rtl_attribute_group;
void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
extern struct rtl_global_var global_var;
int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
bool isht, u8 desc_rate, bool first_ampdu);
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
u8 *sa, u8 *bssid, u16 tid);
#endif
......@@ -104,9 +104,12 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
if (is_hal_stop(rtlhal))
return;
/* 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)) {
rtl_ips_nic_on(hw);
mdelay(1);
}
mutex_lock(&rtlpriv->locks.conf_mutex);
......@@ -167,7 +170,11 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
switch (vif->type) {
switch (ieee80211_vif_type_p2p(vif)) {
case NL80211_IFTYPE_P2P_CLIENT:
mac->p2p = P2P_ROLE_CLIENT;
/*fall through*/
case NL80211_IFTYPE_STATION:
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
......@@ -192,6 +199,9 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
(u8 *) (&mac->basic_rates));
break;
case NL80211_IFTYPE_P2P_GO:
mac->p2p = P2P_ROLE_GO;
/*fall through*/
case NL80211_IFTYPE_AP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"NL80211_IFTYPE_AP\n");
......@@ -205,6 +215,19 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *) (&mac->basic_rates));
break;
case NL80211_IFTYPE_MESH_POINT:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"NL80211_IFTYPE_MESH_POINT\n");
mac->link_state = MAC80211_LINKED;
rtlpriv->cfg->ops->set_bcn_reg(hw);
if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
mac->basic_rates = 0xfff;
else
mac->basic_rates = 0xff0;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *)(&mac->basic_rates));
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"operation mode %d is not supported!\n", vif->type);
......@@ -212,6 +235,13 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
if (mac->p2p) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"p2p role %x\n", vif->type);
mac->basic_rates = 0xff0;/*disable cck rate for p2p*/
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *)(&mac->basic_rates));
}
mac->vif = vif;
mac->opmode = vif->type;
rtlpriv->cfg->ops->set_network_type(hw, vif->type);
......@@ -232,9 +262,9 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&rtlpriv->locks.conf_mutex);
/* Free beacon resources */
if ((mac->opmode == NL80211_IFTYPE_AP) ||
(mac->opmode == NL80211_IFTYPE_ADHOC) ||
(mac->opmode == NL80211_IFTYPE_MESH_POINT)) {
if ((vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_ADHOC) ||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
if (mac->beacon_enabled == 1) {
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
......@@ -247,6 +277,7 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
*Note: We assume NL80211_IFTYPE_UNSPECIFIED as
*NO LINK for our hardware.
*/
mac->p2p = 0;
mac->vif = NULL;
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
......@@ -256,6 +287,22 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
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 rtl_priv *rtlpriv = rtl_priv(hw);
int ret;
rtl_op_remove_interface(hw, vif);
vif->type = new_type;
vif->p2p = p2p;
ret = rtl_op_add_interface(hw, vif);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"p2p %x\n", p2p);
return ret;
}
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
......@@ -264,6 +311,9 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct ieee80211_conf *conf = &hw->conf;
if (mac->skip_scan)
return 1;
mutex_lock(&rtlpriv->locks.conf_mutex);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
......@@ -323,6 +373,16 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_channel *channel = hw->conf.channel;
u8 wide_chan = (u8) channel->hw_value;
if (mac->act_scanning)
mac->n_channels++;
if (rtlpriv->dm.supp_phymode_switch &&
mac->link_state < MAC80211_LINKED &&
!mac->act_scanning) {
if (rtlpriv->cfg->ops->chk_switch_dmdp)
rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
/*
*because we should back channel to
*current_network.chan in in scanning,
......@@ -373,13 +433,13 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
if (wide_chan <= 0)
wide_chan = 1;
/* In scanning, before we go 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 channel
* so we must delay more time to let AP flush these packets
* before going offchannel, or dis-association or delete BA will
* happen by AP
/* In scanning, before we go 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
* channel so we must delay more time to let AP flush these
* packets before going offchannel, or dis-association or
* delete BA will be caused by AP
*/
if (rtlpriv->mac80211.offchan_delay) {
rtlpriv->mac80211.offchan_delay = false;
......@@ -441,7 +501,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
* 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) {
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 {
......@@ -481,32 +542,43 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_sta_info *sta_entry;
if (sta) {
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);
if (rtlhal->current_bandtype == BAND_ON_2_4G) {
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)
if (sta->ht_cap.ht_supported == true)
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)
if (sta->ht_cap.ht_supported == true)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
}
/* I found some times mac80211 give wrong supp_rates for adhoc*/
if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
sta_entry->wireless_mode = WIRELESS_MODE_G;
if (vif->type == NL80211_IFTYPE_ADHOC)
sta_entry->wireless_mode = WIRELESS_MODE_A;
}
/*disable cck rate for p2p*/
if (mac->p2p)
sta->supp_rates[0] &= 0xfffffff0;
memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"Add sta addr is %pM\n", sta->addr);
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
}
return 0;
}
static int rtl_op_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
......@@ -519,9 +591,14 @@ static int rtl_op_sta_remove(struct ieee80211_hw *hw,
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;
......@@ -547,8 +624,8 @@ static int _rtl_get_hal_qnum(u16 queue)
}
/*
*for mac80211 VO=0, VI=1, BE=2, BK=3
*for rtl819x BE=0, BK=1, VI=2, VO=3
*for mac80211 VO = 0, VI = 1, BE = 2, BK = 3
*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,
......@@ -630,6 +707,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
/*TODO: reference to enum ieee80211_bss_change */
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
struct ieee80211_sta *sta = NULL;
/* we should reset all sec info & cam
* before set cam after linked, we should not
* reset in disassoc, that will cause tkip->wep
......@@ -647,23 +725,37 @@ 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);
if (mac->opmode == NL80211_IFTYPE_STATION && sta)
rcu_read_lock();
sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
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);
}
rcu_read_unlock();
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_ASSOC\n");
} else {
if (mac->link_state == MAC80211_LINKED)
rtl_lps_leave(hw);
schedule_work(&rtlpriv->works.lps_leave_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, 6);
/* reset sec info */
rtl_cam_reset_sec_info(hw);
rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
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");
}
......@@ -778,7 +870,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BASIC_RATES) {
/* for 5G must << RATE_6M_INDEX=4,
/* for 5G must << RATE_6M_INDEX = 4,
* because 5G have no cck rate*/
if (rtlhal->current_bandtype == BAND_ON_5G)
basic_rates = sta->supp_rates[1] << 4;
......@@ -815,6 +907,9 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
ppsc->report_linked = false;
}
}
if (rtlpriv->cfg->ops->bt_wifi_media_status_notify)
rtlpriv->cfg->ops->bt_wifi_media_status_notify(hw,
ppsc->report_linked);
}
out:
......@@ -885,7 +980,6 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
return rtl_tx_agg_stop(hw, sta, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid);
......@@ -894,11 +988,11 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_START:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_START:TID:%d\n", tid);
break;
return rtl_rx_agg_start(hw, sta, tid);
case IEEE80211_AMPDU_RX_STOP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid);
break;
return rtl_rx_agg_stop(hw, sta, tid);
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"IEEE80211_AMPDU_ERR!!!!:\n");
......@@ -912,12 +1006,19 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
mac->act_scanning = true;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
mac->act_scanning = true;
if (rtlpriv->link_info.higher_busytraffic) {
mac->skip_scan = true;
return;
}
if (rtlpriv->dm.supp_phymode_switch) {
if (rtlpriv->cfg->ops->chk_switch_dmdp)
rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
if (mac->link_state == MAC80211_LINKED) {
rtl_lps_leave(hw);
schedule_work(&rtlpriv->works.lps_leave_work);
mac->link_state = MAC80211_LINKED_SCANNING;
} else {
rtl_ips_nic_on(hw);
......@@ -937,6 +1038,16 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
mac->act_scanning = false;
mac->skip_scan = false;
if (rtlpriv->link_info.higher_busytraffic)
return;
/*p2p will use 1/6/11 to scan */
if (mac->n_channels == 3)
mac->p2p_in_use = true;
else
mac->p2p_in_use = false;
mac->n_channels = 0;
/* Dual mac */
rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
......@@ -970,6 +1081,11 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
"not open hw encryption\n");
return -ENOSPC; /*User disabled HW-crypto */
}
/* To support IBSS, use sw-crypto for GTK */
if (((vif->type == NL80211_IFTYPE_ADHOC) ||
(vif->type == NL80211_IFTYPE_MESH_POINT)) &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -ENOSPC;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"%s hardware based encryption for keyidx: %d, mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
......@@ -996,6 +1112,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = AESCCMP_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n");
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
/*HW doesn't support CMAC encryption, use software CMAC */
key_type = AESCMAC_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n");
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"HW don't support CMAC encryption, use software CMAC\n");
err = -EOPNOTSUPP;
goto out_unlock;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
key->cipher);
......@@ -1017,13 +1141,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* 1) wep only: is just for wep enc, in this condition
* rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
* will be true & enable_hw_sec will be set when wep
* ke setting.
* key setting.
* 2) wep(group) + AES(pairwise): some AP like cisco
* may use it, in this condition enable_hw_sec will not
* be set when wep key setting */
/* we must reset sec_info after lingked before set key,
* or some flag will be wrong*/
if (mac->opmode == NL80211_IFTYPE_AP) {
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT) {
if (!group_key || key_type == WEP40_ENCRYPTION ||
key_type == WEP104_ENCRYPTION) {
if (group_key)
......@@ -1098,12 +1223,16 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->hw_key_idx = key_idx;
if (key_type == TKIP_ENCRYPTION)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
/*use software CCMP encryption for management frames (MFP) */
if (key_type == AESCCMP_ENCRYPTION)
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
break;
case DISABLE_KEY:
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"disable key delete one entry\n");
/*set local buf about wep key. */
if (mac->opmode == NL80211_IFTYPE_AP) {
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT) {
if (sta)
rtl_cam_del_entry(hw, sta->addr);
}
......@@ -1163,7 +1292,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
}
/* this function is called by mac80211 to flush tx buffer
* before switch channle or power save, or tx buffer packet
* before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
......@@ -1180,6 +1309,7 @@ const struct ieee80211_ops rtl_ops = {
.tx = rtl_op_tx,
.add_interface = rtl_op_add_interface,
.remove_interface = rtl_op_remove_interface,
.change_interface = rtl_op_change_interface,
.config = rtl_op_config,
.configure_filter = rtl_op_configure_filter,
.sta_add = rtl_op_sta_add,
......
......@@ -41,7 +41,10 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
COMP_BEACON | COMP_RATE | COMP_RXDESC | COMP_DIG | COMP_TXAGC |
COMP_POWER | COMP_POWER_TRACKING | COMP_BB_POWERSAVING | COMP_SWAS |
COMP_RF | COMP_TURBO | COMP_RATR | COMP_CMD |
COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN;
COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN |
COMP_EASY_CONCURRENT | COMP_EFUSE | COMP_QOS | COMP_MAC80211 |
COMP_REGD | COMP_CHAN | COMP_BT_COEXIST;
for (i = 0; i < DBGP_TYPE_MAX; i++)
rtlpriv->dbg.dbgp_type[i] = 0;
......
......@@ -135,6 +135,13 @@
#define PHY_TXPWR BIT(8)
#define PHY_PWRDIFF BIT(9)
/* Define Dynamic Mechanism check module bit --> FDM */
#define WA_IOT BIT(0)
#define DM_PWDB BIT(1)
#define DM_MONITOR BIT(2)
#define DM_DIG BIT(3)
#define DM_EDCA_TURBO BIT(4)
enum dbgp_flag_e {
FQOS = 0,
FTX = 1,
......
......@@ -35,8 +35,6 @@ static const u8 MAX_PGPKT_SIZE = 9;
static const u8 PGPKT_DATA_SIZE = 8;
static const int EFUSE_MAX_SIZE = 512;
static const u8 EFUSE_OOB_PROTECT_BYTES = 15;
static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
{0, 0, 0, 2},
{0, 1, 0, 2},
......@@ -240,6 +238,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
u8 rtemp8[1];
u16 efuse_addr = 0;
u8 offset, wren;
u8 u1temp = 0;
u16 i;
u16 j;
const u16 efuse_max_section =
......@@ -285,10 +284,31 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
}
while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {
offset = ((*rtemp8 >> 4) & 0x0f);
/* Check PG header for section num. */
if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */
u1temp = ((*rtemp8 & 0xE0) >> 5);
read_efuse_byte(hw, efuse_addr, rtemp8);
if (offset < efuse_max_section) {
if ((*rtemp8 & 0x0F) == 0x0F) {
efuse_addr++;
read_efuse_byte(hw, efuse_addr, rtemp8);
if (*rtemp8 != 0xFF &&
(efuse_addr < efuse_len)) {
efuse_addr++;
}
continue;
} else {
offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
wren = (*rtemp8 & 0x0F);
efuse_addr++;
}
} else {
offset = ((*rtemp8 >> 4) & 0x0f);
wren = (*rtemp8 & 0x0f);
}
if (offset < efuse_max_section) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
"offset-%d Worden=%x\n", offset, wren);
......@@ -391,7 +411,8 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
efuse_used = rtlefuse->efuse_usedbytes;
if ((totalbytes + efuse_used) >=
(EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
(EFUSE_MAX_SIZE -
rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
result = false;
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
......@@ -932,8 +953,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
u8 badworden = 0x0F;
static int repeat_times;
if (efuse_get_current_size(hw) >=
(EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -
rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
"efuse_pg_packet_write error\n");
return false;
......@@ -949,8 +970,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");
while (continual && (efuse_addr <
(EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
while (continual && (efuse_addr < (EFUSE_MAX_SIZE -
rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
if (write_state == PG_STATE_HEADER) {
badworden = 0x0F;
......@@ -1003,7 +1024,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
}
}
if (efuse_addr >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
if (efuse_addr >= (EFUSE_MAX_SIZE -
rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
"efuse_addr(%#x) Out of size!!\n", efuse_addr);
}
......
......@@ -59,7 +59,7 @@ static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
if (unlikely(ieee80211_is_beacon(fc)))
return BEACON_QUEUE;
if (ieee80211_is_mgmt(fc))
if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return MGNT_QUEUE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
if (ieee80211_is_nullfunc(fc))
......@@ -271,9 +271,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
......@@ -302,8 +299,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
u_pcibridge_aspmsetting);
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
"PlatformEnableASPM(): Write reg[%x] = %x\n",
(pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
u_pcibridge_aspmsetting);
......@@ -349,6 +345,49 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
return status;
}
static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
struct rtl_priv **buddy_priv)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
bool find_buddy_priv = false;
struct rtl_priv *tpriv = NULL;
struct rtl_pci_priv *tpcipriv = NULL;
if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) {
list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list,
list) {
if (tpriv) {
tpcipriv = (struct rtl_pci_priv *)tpriv->priv;
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"pcipriv->ndis_adapter.funcnumber %x\n",
pcipriv->ndis_adapter.funcnumber);
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"tpcipriv->ndis_adapter.funcnumber %x\n",
tpcipriv->ndis_adapter.funcnumber);
if ((pcipriv->ndis_adapter.busnumber ==
tpcipriv->ndis_adapter.busnumber) &&
(pcipriv->ndis_adapter.devnumber ==
tpcipriv->ndis_adapter.devnumber) &&
(pcipriv->ndis_adapter.funcnumber !=
tpcipriv->ndis_adapter.funcnumber)) {
find_buddy_priv = true;
break;
}
}
}
}
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"find_buddy_priv %d\n", find_buddy_priv);
if (find_buddy_priv)
*buddy_priv = tpriv;
return find_buddy_priv;
}
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
......@@ -420,17 +459,14 @@ static void _rtl_pci_io_handler_init(struct device *dev,
}
static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
{
}
static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 additionlen = FCS_LEN;
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct sk_buff *next_skb;
u8 additionlen = FCS_LEN;
/* here open is 4, wep/tkip is 8, aes is 12*/
if (info->control.hw_key)
......@@ -455,7 +491,7 @@ static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
next_skb))
break;
if (tcb_desc->empkt_num >= 5)
if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num)
break;
}
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
......@@ -471,11 +507,17 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info = NULL;
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
int tid;
if (!rtlpriv->rtlhal.earlymode_enable)
return;
if (rtlpriv->dm.supp_phymode_switch &&
(rtlpriv->easy_concurrent_ctl.switch_in_process ||
(rtlpriv->buddy_priv &&
rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process)))
return;
/* we juse use em for BE/BK/VI/VO */
for (tid = 7; tid >= 0; tid--) {
u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)];
......@@ -487,7 +529,8 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
spin_lock_bh(&rtlpriv->locks.waitq_lock);
if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
(ring->entries - skb_queue_len(&ring->queue) > 5)) {
(ring->entries - skb_queue_len(&ring->queue) >
rtlhal->max_earlymode_num)) {
skb = skb_dequeue(&mac->skb_waitq[tid]);
} else {
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
......@@ -525,9 +568,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
HW_DESC_OWN);
/*
*beacon packet will only use the first
*descriptor defautly,and the own may not
/*beacon packet will only use the first
*descriptor by defaut, and the own may not
*be cleared by the hardware
*/
if (own)
......@@ -558,8 +600,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
}
/* for sw LPS, just after NULL skb send out, we can
* sure AP kown we are sleeped, our we should not let
* rf to sleep*/
* sure AP knows we are sleeping, we should not let
* rf sleep
*/
fc = rtl_get_fc(skb);
if (ieee80211_is_nullfunc(fc)) {
if (ieee80211_has_pm(fc)) {
......@@ -569,6 +612,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
rtlpriv->psc.state_inap = false;
}
}
if (ieee80211_is_action(fc)) {
struct ieee80211_mgmt *action_frame =
(struct ieee80211_mgmt *)skb->data;
if (action_frame->u.action.u.ht_smps.action ==
WLAN_HT_ACTION_SMPS) {
dev_kfree_skb(skb);
goto tx_status_ok;
}
}
/* update tid tx pkt num */
tid = rtl_get_tid(skb);
......@@ -637,6 +689,10 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->link_info.num_rx_inperiod++;
}
/* static bcn for roaming */
rtl_beacon_statistic(hw, skb);
rtl_p2p_info(hw, (void *)skb->data, skb->len);
/* for sw lps */
rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
rtl_recognize_peer(hw, (void *)skb->data, skb->len);
......@@ -884,6 +940,16 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
_rtl_pci_rx_interrupt(hw);
}
/*fw related*/
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
"firmware interrupt!\n");
queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.fwevt_wq, 0);
}
}
if (rtlpriv->rtlhal.earlymode_enable)
tasklet_schedule(&rtlpriv->works.irq_tasklet);
......@@ -1458,10 +1524,14 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 i = 0;
int queue_id;
struct rtl8192_tx_ring *ring;
if (mac->skip_scan)
return;
for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
u32 queue_len;
ring = &pcipriv->dev.tx_ring[queue_id];
......@@ -1704,6 +1774,9 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
/* some ARM have no bridge_pdev and will crash here
* so we should check if bridge_pdev is NULL
*/
if (bridge_pdev) {
/*find bridge info if available */
pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
......@@ -1758,6 +1831,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.amd_l1_patch);
rtl_pci_parse_configuration(pdev, hw);
list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list);
return true;
}
......@@ -1804,6 +1878,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, hw);
rtlpriv = hw->priv;
rtlpriv->hw = hw;
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
init_completion(&rtlpriv->firmware_loading_complete);
......@@ -1812,6 +1887,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
rtlpriv->rtlhal.interface = INTF_PCI;
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
rtlpriv->glb_var = &global_var;
/*
*init dbgp flags before all
......@@ -1916,7 +1992,6 @@ int rtl_pci_probe(struct pci_dev *pdev,
fail3:
rtl_deinit_core(hw);
_rtl_pci_io_handler_release(hw);
if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
......@@ -1965,14 +2040,15 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtl_pci_deinit(hw);
rtl_deinit_core(hw);
_rtl_pci_io_handler_release(hw);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
if (rtlpci->irq_alloc) {
synchronize_irq(rtlpci->pdev->irq);
free_irq(rtlpci->pdev->irq, hw);
rtlpci->irq_alloc = 0;
}
list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
pci_release_regions(pdev);
......@@ -2034,6 +2110,7 @@ struct rtl_intf_ops rtl_pci_ops = {
.read_efuse_byte = read_efuse_byte,
.adapter_start = rtl_pci_start,
.adapter_stop = rtl_pci_stop,
.check_buddy_priv = rtl_pci_check_buddy_priv,
.adapter_tx = rtl_pci_tx,
.flush = rtl_pci_flush,
.reset_trx_ring = rtl_pci_reset_trx_ring,
......
......@@ -175,6 +175,7 @@ struct rtl_pci {
/*irq */
u8 irq_alloc;
u32 irq_mask[2];
u32 sys_irq_mask;
/*Bcn control register setting */
u32 reg_bcn_ctrl_val;
......
......@@ -180,6 +180,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
return;
}
if (mac->p2p_in_use)
return;
if (mac->link_state > MAC80211_NOLINK)
return;
......@@ -189,6 +192,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
if (rtlpriv->sec.being_setkey)
return;
if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
if (ppsc->inactiveps) {
rtstate = ppsc->rfpwr_state;
......@@ -231,6 +237,9 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
&rtlpriv->works.ips_nic_off_wq, MSECS(100));
}
/* NOTICE: any opmode should exc nic_on, or disable without
* nic_on may something wrong, like adhoc TP
*/
void rtl_ips_nic_on(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
......@@ -299,7 +308,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
u8 rpwm_val, fw_pwrmode;
bool enter_fwlps;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return;
......@@ -324,43 +333,31 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
*/
if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
bool fw_current_inps;
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS leave ps_mode:%x\n",
FW_PS_ACTIVE_MODE);
rpwm_val = 0x0C; /* RF on */
fw_pwrmode = FW_PS_ACTIVE_MODE;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
&rpwm_val);
enter_fwlps = false;
ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
ppsc->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
&fw_pwrmode);
fw_current_inps = false;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_PSMODE_STATUS,
(u8 *) (&fw_current_inps));
HW_VAR_FW_LPS_ACTION,
(u8 *)(&enter_fwlps));
if (ppsc->p2p_ps_info.opp_ps)
rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else {
if (rtl_get_fwlps_doze(hw)) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS enter ps_mode:%x\n",
ppsc->fwctrl_psmode);
rpwm_val = 0x02; /* RF off */
fw_current_inps = true;
enter_fwlps = true;
ppsc->pwr_mode = ppsc->fwctrl_psmode;
ppsc->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_PSMODE_STATUS,
(u8 *) (&fw_current_inps));
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
&ppsc->fwctrl_psmode);
HW_VAR_FW_LPS_ACTION,
(u8 *)(&enter_fwlps));
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_SET_RPWM,
&rpwm_val);
} else {
/* Reset the power save related parameters. */
ppsc->dot11_psmode = EACTIVE;
......@@ -642,3 +639,286 @@ void rtl_swlps_wq_callback(void *data)
rtlpriv->psc.state = ps;
}
}
static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_mgmt *mgmt = (void *)data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
u8 *pos, *end, *ie;
u16 noa_len;
static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
u8 noa_num, index, i, noa_index = 0;
bool find_p2p_ie = false , find_p2p_ps_ie = false;
pos = (u8 *)mgmt->u.beacon.variable;
end = data + len;
ie = NULL;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
return;
if (pos[0] == 221 && pos[1] > 4) {
if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
ie = pos + 2+4;
break;
}
}
pos += 2 + pos[1];
}
if (ie == NULL)
return;
find_p2p_ie = true;
/*to find noa ie*/
while (ie + 1 < end) {
noa_len = READEF2BYTE(&ie[1]);
if (ie + 3 + ie[1] > end)
return;
if (ie[0] == 12) {
find_p2p_ps_ie = true;
if ((noa_len - 2) % 13 != 0) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"P2P notice of absence: invalid length.%d\n",
noa_len);
return;
} else {
noa_num = (noa_len - 2) / 13;
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
"update NOA ie.\n");
p2pinfo->noa_index = noa_index;
p2pinfo->opp_ps = (ie[4] >> 7);
p2pinfo->ctwindow = ie[4] & 0x7F;
p2pinfo->noa_num = noa_num;
index = 5;
for (i = 0; i < noa_num; i++) {
p2pinfo->noa_count_type[i] =
READEF1BYTE(ie+index);
index += 1;
p2pinfo->noa_duration[i] =
READEF4BYTE(ie+index);
index += 4;
p2pinfo->noa_interval[i] =
READEF4BYTE(ie+index);
index += 4;
p2pinfo->noa_start_time[i] =
READEF4BYTE(ie+index);
index += 4;
}
if (p2pinfo->opp_ps == 1) {
p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
/* Driver should wait LPS entering
* CTWindow
*/
if (rtlpriv->psc.fw_current_inpsmode)
rtl_p2p_ps_cmd(hw,
P2P_PS_ENABLE);
} else if (p2pinfo->noa_num > 0) {
p2pinfo->p2p_ps_mode = P2P_PS_NOA;
rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
break;
}
ie += 3 + noa_len;
}
if (find_p2p_ie == true) {
if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
(find_p2p_ps_ie == false))
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_mgmt *mgmt = (void *)data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
u8 noa_num, index, i, noa_index = 0;
u8 *pos, *end, *ie;
u16 noa_len;
static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
pos = (u8 *)&mgmt->u.action.category;
end = data + len;
ie = NULL;
if (pos[0] == 0x7f) {
if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
ie = pos + 3+4;
}
if (ie == NULL)
return;
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
/*to find noa ie*/
while (ie + 1 < end) {
noa_len = READEF2BYTE(&ie[1]);
if (ie + 3 + ie[1] > end)
return;
if (ie[0] == 12) {
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
ie, noa_len);
if ((noa_len - 2) % 13 != 0) {
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
"P2P notice of absence: invalid length.%d\n",
noa_len);
return;
} else {
noa_num = (noa_len - 2) / 13;
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
p2pinfo->noa_index = noa_index;
p2pinfo->opp_ps = (ie[4] >> 7);
p2pinfo->ctwindow = ie[4] & 0x7F;
p2pinfo->noa_num = noa_num;
index = 5;
for (i = 0; i < noa_num; i++) {
p2pinfo->noa_count_type[i] =
READEF1BYTE(ie+index);
index += 1;
p2pinfo->noa_duration[i] =
READEF4BYTE(ie+index);
index += 4;
p2pinfo->noa_interval[i] =
READEF4BYTE(ie+index);
index += 4;
p2pinfo->noa_start_time[i] =
READEF4BYTE(ie+index);
index += 4;
}
if (p2pinfo->opp_ps == 1) {
p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
/* Driver should wait LPS entering
* CTWindow
*/
if (rtlpriv->psc.fw_current_inpsmode)
rtl_p2p_ps_cmd(hw,
P2P_PS_ENABLE);
} else if (p2pinfo->noa_num > 0) {
p2pinfo->p2p_ps_mode = P2P_PS_NOA;
rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
break;
}
ie += 3 + noa_len;
}
}
void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
switch (p2p_ps_state) {
case P2P_PS_DISABLE:
p2pinfo->p2p_ps_state = p2p_ps_state;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
p2pinfo->noa_index = 0;
p2pinfo->ctwindow = 0;
p2pinfo->opp_ps = 0;
p2pinfo->noa_num = 0;
p2pinfo->p2p_ps_mode = P2P_PS_NONE;
if (rtlps->fw_current_inpsmode == true) {
if (rtlps->smart_ps == 0) {
rtlps->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
(u8 *)(&rtlps->pwr_mode));
}
}
break;
case P2P_PS_ENABLE:
if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
p2pinfo->p2p_ps_state = p2p_ps_state;
if (p2pinfo->ctwindow > 0) {
if (rtlps->smart_ps != 0) {
rtlps->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
(u8 *)(&rtlps->pwr_mode));
}
}
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
}
break;
case P2P_PS_SCAN:
case P2P_PS_SCAN_DONE:
case P2P_PS_ALLSTASLEEP:
if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
p2pinfo->p2p_ps_state = p2p_ps_state;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
}
break;
default:
break;
}
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
"ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
"count %x duration %x index %x interval %x start time %x noa num %x\n",
p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
p2pinfo->noa_index, p2pinfo->noa_interval[0],
p2pinfo->noa_start_time[0], p2pinfo->noa_num);
RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
}
void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct ieee80211_hdr *hdr = (void *)data;
if (!mac->p2p)
return;
if (mac->link_state != MAC80211_LINKED)
return;
/* min. beacon length + FCS_LEN */
if (len <= 40 + FCS_LEN)
return;
/* and only beacons from the associated BSSID, please */
if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
return;
/* check if this really is a beacon */
if (!(ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control) ||
ieee80211_is_action(hdr->frame_control)))
return;
if (ieee80211_is_action(hdr->frame_control))
rtl_p2p_action_ie(hw, data, len - FCS_LEN);
else
rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
}
......@@ -47,5 +47,7 @@ void rtl_swlps_wq_callback(void *data);
void rtl_swlps_rfon_wq_callback(void *data);
void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
#endif
......@@ -104,6 +104,7 @@
/* for early mode */
#define FCS_LEN 4
#define EM_HDR_LEN 8
enum intf_type {
INTF_PCI = 0,
INTF_USB = 1,
......@@ -263,7 +264,7 @@ enum hw_variables {
HW_VAR_RATR_0,
HW_VAR_RRSR,
HW_VAR_CPU_RST,
HW_VAR_CECHK_BSSID,
HW_VAR_CHECK_BSSID,
HW_VAR_LBK_MODE,
HW_VAR_AES_11N_FIX,
HW_VAR_USB_RX_AGGR,
......@@ -278,7 +279,10 @@ enum hw_variables {
HW_VAR_SET_RPWM,
HW_VAR_H2C_FW_PWRMODE,
HW_VAR_H2C_FW_JOINBSSRPT,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
HW_VAR_FW_PSMODE_STATUS,
HW_VAR_RESUME_CLK_ON,
HW_VAR_FW_LPS_ACTION,
HW_VAR_1X1_RECV_COMBINE,
HW_VAR_STOP_SEND_BEACON,
HW_VAR_TSF_TIMER,
......@@ -305,6 +309,7 @@ enum hw_variables {
HW_VAR_INT_AC,
HW_VAR_RF_TIMING,
HAL_DEF_WOWLAN,
HW_VAR_MRC,
HW_VAR_MGT_FILTER,
......@@ -461,6 +466,7 @@ enum rtl_var_map {
EFUSE_MAX_SECTION_MAP,
EFUSE_REAL_CONTENT_SIZE,
EFUSE_OOB_PROTECT_BYTES_LEN,
EFUSE_ACCESS,
/*CAM map */
RWCAM,
......@@ -742,6 +748,11 @@ struct false_alarm_statistics {
u32 cnt_ofdm_fail;
u32 cnt_cck_fail;
u32 cnt_all;
u32 cnt_ofdm_cca;
u32 cnt_cck_cca;
u32 cnt_cca_all;
u32 cnt_bw_usc;
u32 cnt_bw_lsc;
};
struct init_gain {
......@@ -826,8 +837,67 @@ struct rtl_rfkill {
bool rfkill_state; /*0 is off, 1 is on */
};
/*for P2P PS**/
#define P2P_MAX_NOA_NUM 2
enum p2p_role {
P2P_ROLE_DISABLE = 0,
P2P_ROLE_DEVICE = 1,
P2P_ROLE_CLIENT = 2,
P2P_ROLE_GO = 3
};
enum p2p_ps_state {
P2P_PS_DISABLE = 0,
P2P_PS_ENABLE = 1,
P2P_PS_SCAN = 2,
P2P_PS_SCAN_DONE = 3,
P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
};
enum p2p_ps_mode {
P2P_PS_NONE = 0,
P2P_PS_CTWINDOW = 1,
P2P_PS_NOA = 2,
P2P_PS_MIX = 3, /* CTWindow and NoA */
};
struct rtl_p2p_ps_info {
enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */
enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */
u8 noa_index; /* Identifies instance of Notice of Absence timing. */
/* Client traffic window. A period of time in TU after TBTT. */
u8 ctwindow;
u8 opp_ps; /* opportunistic power save. */
u8 noa_num; /* number of NoA descriptor in P2P IE. */
/* Count for owner, Type of client. */
u8 noa_count_type[P2P_MAX_NOA_NUM];
/* Max duration for owner, preferred or min acceptable duration
* for client.
*/
u32 noa_duration[P2P_MAX_NOA_NUM];
/* Length of interval for owner, preferred or max acceptable intervali
* of client.
*/
u32 noa_interval[P2P_MAX_NOA_NUM];
/* schedule in terms of the lower 4 bytes of the TSF timer. */
u32 noa_start_time[P2P_MAX_NOA_NUM];
};
struct p2p_ps_offload_t {
u8 offload_en:1;
u8 role:1; /* 1: Owner, 0: Client */
u8 ctwindow_en:1;
u8 noa0_en:1;
u8 noa1_en:1;
u8 allstasleep:1;
u8 discovery:1;
u8 reserved:1;
};
#define IQK_MATRIX_REG_NUM 8
#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21)
struct iqk_matrix_regs {
bool iqk_done;
long value[1][IQK_MATRIX_REG_NUM];
......@@ -902,6 +972,8 @@ struct rtl_phy {
/* the current Tx power level */
u8 cur_cck_txpwridx;
u8 cur_ofdm24g_txpwridx;
u8 cur_bw20_txpwridx;
u8 cur_bw40_txpwridx;
u32 rfreg_chnlval[2];
bool apk_done;
......@@ -940,20 +1012,21 @@ struct rtl_ht_agg {
u8 rx_agg_state;
};
struct rssi_sta {
long undec_sm_pwdb;
};
struct rtl_tid_data {
u16 seq_number;
struct rtl_ht_agg agg;
};
struct rssi_sta {
long undec_sm_pwdb;
};
struct rtl_sta_info {
struct list_head list;
u8 ratr_index;
u8 wireless_mode;
u8 mimo_ps;
u8 mac_addr[ETH_ALEN];
struct rtl_tid_data tids[MAX_TID_COUNT];
/* just used for ap adhoc or mesh*/
......@@ -1005,6 +1078,8 @@ struct rtl_mac {
int n_bitrates;
bool offchan_delay;
u8 p2p; /*using p2p role*/
bool p2p_in_use;
/*filters */
u32 rx_conf;
......@@ -1014,11 +1089,11 @@ struct rtl_mac {
bool act_scanning;
u8 cnt_after_linked;
bool skip_scan;
/* early mode */
/* skb wait queue */
struct sk_buff_head skb_waitq[MAX_TID_COUNT];
u8 earlymode_threshold;
/*RDG*/
bool rdg_en;
......@@ -1042,6 +1117,7 @@ struct rtl_mac {
u8 retry_short;
u8 retry_long;
u16 assoc_id;
bool hiddenssid;
/*IBSS*/
int beacon_interval;
......@@ -1111,10 +1187,13 @@ struct bt_coexist_8723 {
struct rtl_hal {
struct ieee80211_hw *hw;
struct bt_coexist_8723 hal_coex_8723;
bool driver_is_goingto_unload;
bool up_first_time;
bool first_init;
bool being_init_adapter;
bool bbrf_ready;
bool mac_func_enable;
struct bt_coexist_8723 hal_coex_8723;
enum intf_type interface;
u16 hw_type; /*92c or 92d or 92s and so on */
......@@ -1122,6 +1201,7 @@ struct rtl_hal {
u8 oem_id;
u32 version; /*version of chip */
u8 state; /*stop 0, start 1 */
u8 board_type;
/*firmware */
u32 fwsize;
......@@ -1141,6 +1221,10 @@ struct rtl_hal {
bool set_fwcmd_inprogress;
u8 current_fwcmd_io;
bool fw_clk_change_in_progress;
bool allow_sw_to_change_hwclc;
u8 fw_ps_state;
struct p2p_ps_offload_t p2p_ps_offload;
/**/
bool driver_going2unload;
......@@ -1157,6 +1241,7 @@ struct rtl_hal {
/* just for DualMac S3S4 */
u8 macphyctl_reg;
bool earlymode_enable;
u8 max_earlymode_num;
/* Dual mac*/
bool during_mac0init_radiob;
bool during_mac1init_radioa;
......@@ -1341,6 +1426,7 @@ struct rtl_ps_ctl {
bool fw_current_inpsmode;
u8 reg_max_lps_awakeintvl;
bool report_linked;
bool low_power_enable;/*for 32k*/
/*for IPS */
bool inactiveps;
......@@ -1373,6 +1459,11 @@ struct rtl_ps_ctl {
unsigned long last_beacon;
unsigned long last_action;
unsigned long last_slept;
/*For P2P PS */
struct rtl_p2p_ps_info p2p_ps_info;
u8 pwr_mode;
u8 smart_ps;
};
struct rtl_stats {
......@@ -1553,7 +1644,7 @@ struct rtl_hal_ops {
void (*allow_all_destaddr)(struct ieee80211_hw *hw,
bool allow_all_da, bool write_into_reg);
void (*linked_set_reg) (struct ieee80211_hw *hw);
void (*check_switch_to_dmdp) (struct ieee80211_hw *hw);
void (*chk_switch_dmdp) (struct ieee80211_hw *hw);
void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw);
void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw);
bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
......@@ -1662,6 +1753,8 @@ struct rtl_locks {
/*spin lock */
spinlock_t ips_lock;
spinlock_t irq_th_lock;
spinlock_t irq_pci_lock;
spinlock_t tx_lock;
spinlock_t h2c_lock;
spinlock_t rf_ps_lock;
spinlock_t rf_lock;
......@@ -1670,6 +1763,9 @@ struct rtl_locks {
spinlock_t entry_list_lock;
spinlock_t usb_lock;
/*FW clock change */
spinlock_t fw_ps_lock;
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;
......@@ -1683,6 +1779,8 @@ struct rtl_works {
/*timer */
struct timer_list watchdog_timer;
struct timer_list dualmac_easyconcurrent_retrytimer;
struct timer_list fw_clockoff_timer;
struct timer_list fast_antenna_training_timer;
/*task */
struct tasklet_struct irq_tasklet;
......@@ -1696,6 +1794,7 @@ struct rtl_works {
/* For SW LPS */
struct delayed_work ps_work;
struct delayed_work ps_rfon_wq;
struct delayed_work fwevt_wq;
struct work_struct lps_leave_work;
};
......@@ -1802,6 +1901,7 @@ struct rtl_global_var {
};
struct rtl_priv {
struct ieee80211_hw *hw;
struct completion firmware_loading_complete;
struct list_head list;
struct rtl_priv *buddy_priv;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment