summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rsi/rsi_91x_hal.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_hal.c')
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_hal.c136
1 files changed, 119 insertions, 17 deletions
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index b0a7a1511aee..070dfd68bb83 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -18,6 +18,7 @@
#include "rsi_mgmt.h"
#include "rsi_hal.h"
#include "rsi_sdio.h"
+#include "rsi_common.h"
/* FLASH Firmware */
static struct ta_metadata metadata_flash_content[] = {
@@ -25,7 +26,15 @@ static struct ta_metadata metadata_flash_content[] = {
{"rsi/rs9113_wlan_qspi.rps", 0x00010000},
};
-/*This function prepares descriptor for given management packet*/
+int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = common->priv;
+ int status;
+
+ status = adapter->host_intf_ops->write_pkt(common->priv,
+ skb->data, skb->len);
+ return status;
+}
static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
{
@@ -33,7 +42,7 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
struct ieee80211_hdr *wh = NULL;
struct ieee80211_tx_info *info;
struct ieee80211_conf *conf = &adapter->hw->conf;
- struct ieee80211_vif *vif = NULL;
+ struct ieee80211_vif *vif = adapter->vifs[0];
struct rsi_mgmt_desc *mgmt_desc;
struct skb_info *tx_params;
struct ieee80211_bss_conf *bss = NULL;
@@ -41,6 +50,11 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
u8 header_size;
u32 dword_align_bytes = 0;
+ if (skb->len > MAX_MGMT_PKT_SIZE) {
+ rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
+ return -EINVAL;
+ }
+
info = IEEE80211_SKB_CB(skb);
tx_params = (struct skb_info *)info->driver_data;
@@ -66,15 +80,10 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
memset(&skb->data[0], 0, header_size);
bss = &info->control.vif->bss_conf;
wh = (struct ieee80211_hdr *)&skb->data[header_size];
- vif = adapter->vifs[0];
mgmt_desc = (struct rsi_mgmt_desc *)skb->data;
xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ];
- if (skb->len > MAX_MGMT_PKT_SIZE) {
- rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
- return -EINVAL;
- }
rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
RSI_WIFI_MGMT_Q);
mgmt_desc->frame_type = TX_DOT11_MGMT;
@@ -105,12 +114,30 @@ static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
}
}
+ if (ieee80211_is_probe_resp(wh->frame_control)) {
+ mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID |
+ RSI_FETCH_RETRY_CNT_FRM_HST);
+#define PROBE_RESP_RETRY_CNT 3
+ xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT;
+ }
+
+ if ((vif->type == NL80211_IFTYPE_AP) &&
+ (ieee80211_is_action(wh->frame_control))) {
+ struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1);
+
+ if (rsta)
+ mgmt_desc->sta_id = tx_params->sta_id;
+ else
+ return -EINVAL;
+ }
return 0;
}
/* This function prepares descriptor for given data packet */
static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
{
+ struct rsi_hw *adapter = common->priv;
+ struct ieee80211_vif *vif;
struct ieee80211_hdr *wh = NULL;
struct ieee80211_tx_info *info;
struct skb_info *tx_params;
@@ -147,7 +174,8 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ];
wh = (struct ieee80211_hdr *)&skb->data[header_size];
- seq_num = (le16_to_cpu(wh->seq_ctrl) >> 4);
+ seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl));
+ vif = adapter->vifs[0];
data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;
@@ -156,6 +184,10 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE);
}
+ if ((vif->type == NL80211_IFTYPE_STATION) &&
+ (adapter->ps_state == PS_ENABLED))
+ wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
+
if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
(common->secinfo.security_enable)) {
if (rsi_is_cipher_wep(common))
@@ -176,12 +208,11 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
if (conf_is_ht40(&common->priv->hw->conf))
data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
- if (common->vif_info[0].sgi) {
- if (common->min_rate & 0x100) /* Only MCS rates */
- data_desc->rate_info |=
- cpu_to_le16(ENABLE_SHORTGI_RATE);
+ if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) {
+ /* Only MCS rates */
+ data_desc->rate_info |=
+ cpu_to_le16(ENABLE_SHORTGI_RATE);
}
-
}
if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
@@ -208,7 +239,17 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT);
data_desc->sta_id = vap_id;
+
+ if (vif->type == NL80211_IFTYPE_AP) {
+ if (common->band == NL80211_BAND_5GHZ)
+ data_desc->rate_info = cpu_to_le16(RSI_RATE_6);
+ else
+ data_desc->rate_info = cpu_to_le16(RSI_RATE_1);
+ }
}
+ if ((vif->type == NL80211_IFTYPE_AP) &&
+ (ieee80211_has_moredata(wh->frame_control)))
+ data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT);
return 0;
}
@@ -217,17 +258,23 @@ static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
{
struct rsi_hw *adapter = common->priv;
+ struct ieee80211_vif *vif = adapter->vifs[0];
struct ieee80211_tx_info *info;
struct ieee80211_bss_conf *bss;
- int status = -EIO;
+ int status = -EINVAL;
+
+ if (!skb)
+ return 0;
+ if (common->iface_down)
+ goto err;
info = IEEE80211_SKB_CB(skb);
+ if (!info->control.vif)
+ goto err;
bss = &info->control.vif->bss_conf;
- if (!bss->assoc) {
- status = -EINVAL;
+ if ((vif->type == NL80211_IFTYPE_STATION) && (!bss->assoc))
goto err;
- }
status = rsi_prepare_data_desc(common, skb);
if (status)
@@ -299,6 +346,61 @@ err:
return status;
}
+int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
+{
+ struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
+ struct rsi_data_desc *bcn_frm;
+ struct ieee80211_hw *hw = common->priv->hw;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct sk_buff *mac_bcn;
+ u8 vap_id = 0;
+ u16 tim_offset;
+
+ mac_bcn = ieee80211_beacon_get_tim(adapter->hw,
+ adapter->vifs[adapter->sc_nvifs - 1],
+ &tim_offset, NULL);
+ if (!mac_bcn) {
+ rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n");
+ return -EINVAL;
+ }
+
+ common->beacon_cnt++;
+ bcn_frm = (struct rsi_data_desc *)skb->data;
+ rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q);
+ bcn_frm->header_len = MIN_802_11_HDR_LEN;
+ bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO |
+ RSI_DATA_DESC_NO_ACK_IND |
+ RSI_DATA_DESC_BEACON_FRAME |
+ RSI_DATA_DESC_INSERT_TSF |
+ RSI_DATA_DESC_INSERT_SEQ_NO |
+ RATE_INFO_ENABLE);
+ bcn_frm->rate_info = cpu_to_le16(vap_id << 14);
+ bcn_frm->qid_tid = BEACON_HW_Q;
+
+ if (conf_is_ht40_plus(conf)) {
+ bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE);
+ bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12);
+ } else if (conf_is_ht40_minus(conf)) {
+ bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE);
+ bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12);
+ }
+
+ if (common->band == NL80211_BAND_2GHZ)
+ bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1);
+ else
+ bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6);
+
+ if (mac_bcn->data[tim_offset + 2] == 0)
+ bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
+
+ memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len);
+ skb_put(skb, mac_bcn->len + FRAME_DESC_SZ);
+
+ dev_kfree_skb(mac_bcn);
+
+ return 0;
+}
+
static void bl_cmd_timeout(unsigned long priv)
{
struct rsi_hw *adapter = (struct rsi_hw *)priv;