diff mbox

[3.13.1,8/9] rsi: Management frames internal to device

Message ID 52EB4FEB.4060105@redpinesignals.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Jahnavi Jan. 31, 2014, 7:25 a.m. UTC
From: Jahnavi Meher <jahnavi.meher@redpinesignals.com>

This patch has the functions which prepare mgmt frames
that are internal to the device and also handle exchange
of these internal mgmt frames with the device.

Signed-off-by: Jahnavi Meher <jahnavi.meher@redpinesignals.com>
---

rsi_91x_mgmt.c | 1345 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1345 insertions(+)




    
  



--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff -uprN a/drivers/net/wireless/rsi/91x/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/91x/rsi_91x_mgmt.c
--- a/drivers/net/wireless/rsi/91x/rsi_91x_mgmt.c	1970-01-01 05:30:00.000000000 +0530
+++ b/drivers/net/wireless/rsi/91x/rsi_91x_mgmt.c	2014-01-30 16:26:31.911451234 +0530
@@ -0,0 +1,1345 @@ 
+/**
+ * @file rsi_91x_mgmt.c
+ * @author
+ * @version 1.0
+ *
+ * @section LICENSE
+ * Copyright (c) 2013 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * @section DESCRIPTION
+ *
+ * The file contains the message information exchanged between the
+ * driver and underlying device.
+ */
+
+#include "../include/rsi_main.h"
+#include "../include/rsi_hw_intf.h"
+#include "../include/rsi_device_ops.h"
+#include "../include/rsi_mgmt.h"
+#include "../include/rsi_mac80211.h"
+
+static struct bootup_params boot_params_20 = {
+	.magic_number = cpu_to_le16(0x5aa5),
+	.crystal_good_time = 0x0,
+	.valid = cpu_to_le32(VALID_20),
+	.reserved_for_valids = 0x0,
+	.bootup_mode_info = 0x0,
+	.digital_loop_back_params = 0x0,
+	.rtls_timestamp_en = 0x0,
+	.host_spi_intr_cfg = 0x0,
+	.device_clk_info = {{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+					      (TA_PLL_M_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+					      (PLL960_N_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = cpu_to_le16(0x9f0),
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x0,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x1,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = cpu_to_le16(0x121),
+			.umac_clock_reg_config = 0x0,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	},
+	{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+					      (TA_PLL_M_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+					      (PLL960_N_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = cpu_to_le16(0x9f0),
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x0,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x0,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = 0x0,
+			.umac_clock_reg_config = 0x0,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	},
+	{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = cpu_to_le16((TA_PLL_N_VAL_20 << 8)|
+					      (TA_PLL_M_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(TA_PLL_P_VAL_20),
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = cpu_to_le16((PLL960_P_VAL_20 << 8)|
+					      (PLL960_N_VAL_20)),
+				.pll_reg_2 = cpu_to_le16(PLL960_M_VAL_20),
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = cpu_to_le16(0x9f0),
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x0,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x0,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = 0x0,
+			.umac_clock_reg_config = 0x0,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	} },
+	.buckboost_wakeup_cnt = 0x0,
+	.pmu_wakeup_wait = 0x0,
+	.shutdown_wait_time = 0x0,
+	.pmu_slp_clkout_sel = 0x0,
+	.wdt_prog_value = 0x0,
+	.wdt_soc_rst_delay = 0x0,
+	.dcdc_operation_mode = 0x0,
+	.soc_reset_wait_cnt = 0x0
+};
+
+static struct bootup_params boot_params_40 = {
+	.magic_number = 0x5aa5,
+	.crystal_good_time = 0x0,
+	.valid = VALID_40,
+	.reserved_for_valids = 0x0,
+	.bootup_mode_info = 0x0,
+	.digital_loop_back_params = 0x0,
+	.rtls_timestamp_en = 0x0,
+	.host_spi_intr_cfg = 0x0,
+	.device_clk_info = {{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = ((TA_PLL_N_VAL_40 << 8) |
+					      (TA_PLL_M_VAL_40)),
+				.pll_reg_2 = (TA_PLL_P_VAL_40),
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = ((PLL960_P_VAL_40 << 8) |
+					      (PLL960_N_VAL_40)),
+				.pll_reg_2 = PLL960_M_VAL_40,
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = 0x9f0,
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x1,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x1,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = 0x1121,
+			.umac_clock_reg_config = 0x48,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	},
+	{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = ((TA_PLL_N_VAL_40 << 8) |
+					      (TA_PLL_M_VAL_40)),
+				.pll_reg_2 = (TA_PLL_P_VAL_40)
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = ((PLL960_P_VAL_40 << 8) |
+					      (PLL960_N_VAL_40)),
+				.pll_reg_2 = PLL960_M_VAL_40,
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = 0x9f0,
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x0,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x0,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = 0x0,
+			.umac_clock_reg_config = 0x0,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	},
+	{
+		.pll_config_g = {
+			.tapll_info_g = {
+				.pll_reg_1 = ((TA_PLL_N_VAL_40 << 8) |
+					      (TA_PLL_M_VAL_40)),
+				.pll_reg_2 = (TA_PLL_P_VAL_40),
+			},
+			.pll960_info_g = {
+				.pll_reg_1 = ((PLL960_P_VAL_40 << 8) |
+					      (PLL960_N_VAL_40)),
+				.pll_reg_2 = PLL960_M_VAL_40,
+				.pll_reg_3 = 0x0,
+			},
+			.afepll_info_g = {
+				.pll_reg = 0x9f0,
+			}
+		},
+		.switch_clk_g = {
+			.switch_umac_clk = 0x0,
+			.switch_qspi_clk = 0x0,
+			.switch_slp_clk_2_32 = 0x0,
+			.switch_bbp_lmac_clk_reg = 0x0,
+			.switch_mem_ctrl_cfg = 0x0,
+			.reserved = 0x0,
+			.bbp_lmac_clk_reg_val = 0x0,
+			.umac_clock_reg_config = 0x0,
+			.qspi_uart_clock_reg_config = 0x0
+		}
+	} },
+	.buckboost_wakeup_cnt = 0x0,
+	.pmu_wakeup_wait = 0x0,
+	.shutdown_wait_time = 0x0,
+	.pmu_slp_clkout_sel = 0x0,
+	.wdt_prog_value = 0x0,
+	.wdt_soc_rst_delay = 0x0,
+	.dcdc_operation_mode = 0x0,
+	.soc_reset_wait_cnt = 0x0
+};
+
+static unsigned short mcs[] = {13, 26, 39, 52, 78, 104, 117, 130};
+
+/**
+ * This function sets the contention values for the backoff procedure.
+ *
+ * @param  common Pointer to the driver common structure.
+ * @return None.
+ */
+static void rsi_set_contention_vals(struct rsi_common *common)
+{
+	unsigned char ii = 0;
+
+	for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) {
+		common->tx_qinfo[ii].wme_params =
+			(((common->edca_params[ii].cw_min / 2) +
+			  (common->edca_params[ii].aifs)) *
+			  WMM_SHORT_SLOT_TIME + SIFS_DURATION);
+		common->tx_qinfo[ii].weight = common->tx_qinfo[ii].wme_params;
+		common->tx_qinfo[ii].pkt_contended = 0;
+	}
+}
+
+/**
+ * This function sends management frame to firmware.
+ * Also schedules packet to queue for transmit.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  addr Pointer to rsi mac frame structure.
+ * @param  len Length.
+ * @return 0 on success, -1 on failure.
+ */
+static int rsi_send_internal_mgmt_frame(struct rsi_common *common,
+					struct sk_buff *skb)
+{
+	struct skb_info *tx_params;
+
+	if (skb == NULL) {
+		rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__);
+		return -1;
+	}
+	tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data;
+	tx_params->flags |= INTERNAL_MGMT_PKT;
+	skb_queue_tail(&common->tx_queue[MGMT_SOFT_Q], skb);
+	common->common_ops->set_event(&common->tx_event);
+	return 0;
+}
+
+/**
+ * This function used to send radio capabilities values to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_load_radio_caps(struct rsi_common *common)
+{
+	struct rsi_mac_frame *mgmt_frame;
+	struct rsi_hw *adapter = common->priv;
+	struct ieee80211_hw *hw = adapter->hw;
+	unsigned short inx = 0;
+	unsigned char ii;
+	unsigned char radio_id = 0;
+	unsigned short gc[20] = {0xf0, 0xf0, 0xf0, 0xf0,
+				 0xf0, 0xf0, 0xf0, 0xf0,
+				 0xf0, 0xf0, 0xf0, 0xf0,
+				 0xf0, 0xf0, 0xf0, 0xf0,
+				 0xf0, 0xf0, 0xf0, 0xf0};
+	struct ieee80211_conf *conf = &hw->conf;
+	struct sk_buff *skb;
+
+	rsi_dbg(INFO_ZONE,
+		"%s: Sending rate symbol req frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	mgmt_frame->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES);
+	mgmt_frame->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8);
+
+	if (common->channel_width == BW_40MHZ) {
+		mgmt_frame->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ);
+		mgmt_frame->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ);
+		if (common->channel_width) {
+			mgmt_frame->desc_word[5] =
+				cpu_to_le16(common->channel_width << 12);
+			mgmt_frame->desc_word[5] |= cpu_to_le16(FULL40M_ENABLE);
+		}
+
+		if (conf_is_ht40_minus(conf)) {
+			mgmt_frame->desc_word[5] = 0;
+			mgmt_frame->desc_word[5] |=
+				cpu_to_le16(LOWER_20_ENABLE);
+			mgmt_frame->desc_word[5] |=
+				cpu_to_le16(LOWER_20_ENABLE >> 12);
+		}
+
+		if (conf_is_ht40_plus(conf)) {
+			mgmt_frame->desc_word[5] = 0;
+			mgmt_frame->desc_word[5] |=
+				cpu_to_le16(UPPER_20_ENABLE);
+			mgmt_frame->desc_word[5] |=
+				cpu_to_le16(UPPER_20_ENABLE >> 12);
+		}
+	}
+
+	mgmt_frame->desc_word[7] |= cpu_to_le16(radio_id << 8);
+
+	for (ii = 0; ii < MAX_HW_QUEUES; ii++) {
+		mgmt_frame->u.radio_caps.qos_params[ii].cont_win_min_q =
+			cpu_to_le16(3);
+		mgmt_frame->u.radio_caps.qos_params[ii].cont_win_max_q =
+			cpu_to_le16(0x3f);
+		mgmt_frame->u.radio_caps.qos_params[ii].aifsn_val_q =
+			cpu_to_le16(2);
+		mgmt_frame->u.radio_caps.qos_params[ii].txop_q = 0;
+	}
+
+	for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) {
+		mgmt_frame->u.radio_caps.qos_params[ii].cont_win_min_q =
+			cpu_to_le16(common->edca_params[ii].cw_min);
+		mgmt_frame->u.radio_caps.qos_params[ii].cont_win_max_q =
+			cpu_to_le16(common->edca_params[ii].cw_max);
+		mgmt_frame->u.radio_caps.qos_params[ii].aifsn_val_q =
+			cpu_to_le16((common->edca_params[ii].aifs) << 8);
+		mgmt_frame->u.radio_caps.qos_params[ii].txop_q =
+			cpu_to_le16(common->edca_params[ii].txop);
+	}
+
+	memcpy(&common->rate_pwr[0], &gc[0], 40);
+	for (ii = 0; ii < 20; ii++)
+		mgmt_frame->u.radio_caps.gcpd_per_rate[inx++] =
+			cpu_to_le16(common->rate_pwr[ii]  & 0x00FF);
+
+	mgmt_frame->desc_word[0] = cpu_to_le16(sizeof(mgmt_frame->u.radio_caps)|
+				    (RSI_WIFI_MGMT_Q << 12));
+
+
+	skb_put(skb, (sizeof(mgmt_frame->u.radio_caps) + FRAME_DESC_SZ));
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function is the entry point of Management module.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  msg Pointer to received packet.
+ * @param  msg_len Length of the recieved packet.
+ * @param  type Type of recieved packet.
+ * @return 0 on success, -1 on failure.
+ */
+static int rsi_mgmt_pkt_to_core(struct rsi_common *common,
+				unsigned char *msg,
+				int msg_len,
+				unsigned char type)
+{
+	struct ieee80211_tx_info *info;
+	struct skb_info *rx_params;
+	unsigned char pad_bytes = msg[4];
+	unsigned char pkt_recv;
+	struct sk_buff *skb;
+	char *buffer;
+
+	if (type == RX_DOT11_MGMT) {
+		msg_len -= pad_bytes;
+		if ((msg_len <= 0) || (!msg)) {
+			rsi_dbg(MGMT_RX_ZONE, "Invalid rx msg of len = %d\n",
+				__func__, msg_len);
+			return -1;
+		}
+
+		skb = dev_alloc_skb(msg_len);
+		if (!skb) {
+			rsi_dbg(ERR_ZONE, "%s: Failed to allocate skb\n",
+				__func__);
+			return -1;
+		}
+
+		buffer = skb_put(skb, msg_len);
+
+		memcpy(buffer,
+		       (unsigned char *)(msg +  FRAME_DESC_SZ + pad_bytes),
+		       msg_len);
+
+		pkt_recv = buffer[0];
+
+		if ((pkt_recv != 0x50) && (pkt_recv != 0x80) &&
+		    (pkt_recv != 0x40)) {
+			rsi_dbg(MGMT_RX_ZONE, "%s: ===> MGMT PKT RCVD <===\n",
+				__func__);
+		}
+		info = IEEE80211_SKB_CB(skb);
+		rx_params = (struct skb_info *)info->driver_data;
+		rx_params->rssi = rsi_get_rssi(msg);
+		rx_params->channel = rsi_get_channel(msg);
+		rsi_indicate_pkt_to_os(common, skb);
+	} else {
+		rsi_dbg(MGMT_TX_ZONE, "%s: Internal Packet\n", __func__);
+	}
+
+	return 0;
+}
+
+/**
+ * This function sends station notify frame to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  opmode Operating mode of device.
+ * @param  notify_event Notification about station connection.
+ * @param  bssid bssid.
+ * @param  qos_enable Qos is enabled.
+ * @param  aid Aid (unique for all STA).
+ * @return status: 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_hal_send_sta_notify_frame(struct rsi_common *common,
+					 unsigned char opmode,
+					 unsigned char notify_event,
+					 const unsigned char *bssid,
+					 unsigned char qos_enable,
+					 unsigned short aid)
+{
+	struct sk_buff *skb = NULL;
+	struct rsi_mac_frame *mgmt_frame;
+	unsigned short vap_id = 0;
+	int status;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending sta notify frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	mgmt_frame->u.peer_notify.command = cpu_to_le16(opmode << 1);
+
+	switch (notify_event) {
+	case STA_CONNECTED:
+		mgmt_frame->u.peer_notify.command |= cpu_to_le16(RSI_ADD_PEER);
+		break;
+	case STA_DISCONNECTED:
+		mgmt_frame->u.peer_notify.command |=
+			cpu_to_le16(RSI_DELETE_PEER);
+		break;
+	case STA_TX_ADDBA_DONE:
+	case STA_TX_DELBA:
+	case STA_RX_ADDBA_DONE:
+	case STA_RX_DELBA:
+		break;
+	default:
+		break;
+	}
+
+	mgmt_frame->u.peer_notify.command |= cpu_to_le16((aid & 0xfff) << 4);
+	memcpy(mgmt_frame->u.peer_notify.mac_addr, bssid, ETH_ALEN);
+	mgmt_frame->u.peer_notify.sta_flags = cpu_to_le16((qos_enable) ? 1 : 0);
+
+	mgmt_frame->desc_word[0] =
+		cpu_to_le16(sizeof(mgmt_frame->u.peer_notify) |
+			    (RSI_WIFI_MGMT_Q << 12));
+	mgmt_frame->desc_word[1] = cpu_to_le16(PEER_NOTIFY);
+	mgmt_frame->desc_word[7] |= cpu_to_le16(vap_id << 8);
+
+	skb_put(skb, sizeof(mgmt_frame->u.peer_notify) + FRAME_DESC_SZ);
+
+	status = rsi_send_internal_mgmt_frame(common, skb);
+
+	if ((!status) && (qos_enable)) {
+		rsi_set_contention_vals(common);
+		status = rsi_load_radio_caps(common);
+	}
+	return status;
+}
+
+/**
+ * This function sends ampdu indication frame to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  tid traffic identifier.
+ * @param  ssn ssn.
+ * @param  buf_size buffer size (for kernel version > 2.6.38).
+ * @param  event notification about station connection.
+ * @return 0 on success, corresponding negative error code on failure.
+ */
+int rsi_send_ampdu_indication_frame(struct rsi_common *common,
+				    unsigned short tid,
+				    unsigned short ssn,
+				    unsigned char buf_size,
+				    unsigned char event)
+{
+	struct sk_buff *skb = NULL;
+	struct rsi_mac_frame *mgmt_frame;
+	unsigned char peer_id = 0;
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending AMPDU indication frame\n", __func__);
+
+	mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+	mgmt_frame->desc_word[1] = cpu_to_le16(AMPDU_IND);
+
+	if (event == STA_TX_ADDBA_DONE) {
+		mgmt_frame->desc_word[4] = cpu_to_le16(ssn);
+		mgmt_frame->desc_word[5] = cpu_to_le16(buf_size);
+		mgmt_frame->desc_word[7] =
+		cpu_to_le16((tid | (START_AMPDU_AGGR << 4) | (peer_id << 8)));
+	} else if (event == STA_RX_ADDBA_DONE) {
+		mgmt_frame->desc_word[4] = cpu_to_le16(ssn);
+		mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+						       (START_AMPDU_AGGR << 4) |
+						       (RX_BA_INDICATION << 5) |
+						       (peer_id << 8));
+	} else if (event == STA_TX_DELBA) {
+		mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+						       (STOP_AMPDU_AGGR << 4) |
+						       (peer_id << 8));
+	} else if (event == STA_RX_DELBA) {
+		mgmt_frame->desc_word[7] = cpu_to_le16(tid |
+						       (STOP_AMPDU_AGGR << 4) |
+						       (RX_BA_INDICATION << 5) |
+						       (peer_id << 8));
+	}
+
+	skb_put(skb, FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function starts base band and RF programming.
+ * This is called after initial configurations are done.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, corresponding negative error code on failure.
+ */
+static int rsi_program_bb_rf(struct rsi_common *common)
+{
+	struct sk_buff *skb;
+	struct rsi_mac_frame *mgmt_frame;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending program BB/RF frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+#ifdef USE_USB_INTF
+	mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+#else
+	mgmt_frame->desc_word[0] = cpu_to_le16((FRAME_DESC_SZ) |
+					       (RSI_WIFI_MGMT_Q << 12));
+#endif
+	mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA);
+	mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint << 8);
+
+	if (common->rf_reset) {
+		mgmt_frame->desc_word[7] =  cpu_to_le16(RF_RESET_ENABLE);
+		rsi_dbg(MGMT_TX_ZONE, "%s: ===> RF RESET REQUEST SENT <===\n",
+			__func__);
+		common->rf_reset = 0;
+	}
+	common->bb_rf_prog_count = 1;
+	mgmt_frame->desc_word[7] |= cpu_to_le16(PUT_BBP_RESET |
+				     BBP_REG_WRITE | (RSI_RF_TYPE << 4));
+	skb_put(skb, FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function sends vap capabilities to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  opmode Operating mode of device.
+ * @return 0 on success, corresponding negative error code on failure.
+ */
+int rsi_set_vap_capabilities(struct rsi_common *common,
+			     unsigned char opmode)
+{
+	struct sk_buff *skb = NULL;
+	struct rsi_mac_frame *mgmt_frame;
+	unsigned short vap_id = 0;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	mgmt_frame->desc_word[0] = cpu_to_le16((sizeof(mgmt_frame->u.vap_caps))|
+				    (RSI_WIFI_MGMT_Q << 12));
+	mgmt_frame->desc_word[1] = cpu_to_le16(VAP_CAPABILITIES);
+	mgmt_frame->desc_word[4] = cpu_to_le16(opmode |
+					       (common->channel_width << 8));
+	mgmt_frame->desc_word[7] = cpu_to_le16((vap_id << 8) |
+					       (common->mac_id << 4) |
+					       common->radio_id);
+
+	memcpy(mgmt_frame->u.vap_caps.mac_addr,
+	       common->mac_addr,
+	       IEEE80211_ADDR_LEN);
+	mgmt_frame->u.vap_caps.keep_alive_period = cpu_to_le16(90);
+	mgmt_frame->u.vap_caps.frag_threshold = cpu_to_le16(MAX_FRAG_LEN);
+
+	mgmt_frame->u.vap_caps.rts_threshold =
+		cpu_to_le16(common->rts_threshold);
+	mgmt_frame->u.vap_caps.default_mgmt_rate_bbpinfo = 0;
+	if (conf_is_ht40(&common->priv->hw->conf)) {
+		mgmt_frame->u.vap_caps.default_ctrl_rate_bbpinfo =
+				cpu_to_le16(RSI_RATE_6 | FULL40M_ENABLE << 16);
+	} else {
+		mgmt_frame->u.vap_caps.default_ctrl_rate_bbpinfo =
+			RSI_RATE_6;
+	}
+	mgmt_frame->u.vap_caps.default_data_rate_bbpinfo = cpu_to_le16(0);
+	mgmt_frame->u.vap_caps.beacon_interval = cpu_to_le16(200);
+	mgmt_frame->u.vap_caps.dtim_period = cpu_to_le16(4);
+
+	skb_put(skb, sizeof(mgmt_frame->u.vap_caps) + FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function is used to load the keys within the firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  data Pointer to the key data.
+ * @param  key_len Key length to be loaded.
+ * @param  key_type Type of key: GROUP/PAIRWISE.
+ * @param  key_id Key index.
+ * @param  cipher Type of cipher used.
+ * @return 0 on success, -1 on failure.
+ */
+int rsi_hal_load_key(struct rsi_common *common,
+		     unsigned char *data,
+		     unsigned short key_len,
+		     unsigned char key_type,
+		     unsigned char key_id,
+		     unsigned int cipher)
+{
+	struct sk_buff *skb = NULL;
+	struct rsi_mac_frame *mgmt_frame;
+	unsigned char key_t1 = 0;
+	unsigned short key_descriptor = 0;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending load key frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	switch (key_type) {
+	case RSI_GROUP_KEY:
+		key_t1 = (1 << 1);
+		break;
+	case RSI_PAIRWISE_KEY:
+		key_t1 = (0 << 1);
+		if ((cipher != WLAN_CIPHER_SUITE_WEP40) &&
+		    (cipher != WLAN_CIPHER_SUITE_WEP104))
+			key_id = 0;
+		break;
+	}
+
+	key_descriptor |= (key_t1 | BIT(13) | (key_id << 14));
+	if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+	    (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+		key_len += 1;
+		key_descriptor |= BIT(2);
+		if (key_len >= 13)
+			key_descriptor |= BIT(3);
+	} else if (cipher != KEY_TYPE_CLEAR) {
+		key_descriptor |= BIT(4);
+		if (cipher == WLAN_CIPHER_SUITE_TKIP)
+			key_descriptor |= BIT(5);
+	}
+
+	mgmt_frame->desc_word[0] = cpu_to_le16(sizeof(mgmt_frame->u.set_key) |
+				    (RSI_WIFI_MGMT_Q << 12));
+	mgmt_frame->desc_word[1] = cpu_to_le16(SET_KEY_REQ);
+	mgmt_frame->desc_word[4] = cpu_to_le16(key_descriptor);
+
+	if ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
+	    (cipher == WLAN_CIPHER_SUITE_WEP104)) {
+		memcpy(&mgmt_frame->u.set_key.key[key_id][1],
+		       data,
+		       key_len * 2);
+	} else {
+		memcpy(&mgmt_frame->u.set_key.key[0][0], data, key_len);
+	}
+
+	memcpy(&mgmt_frame->u.set_key.tx_mic_key, &data[16], 8);
+	memcpy(&mgmt_frame->u.set_key.rx_mic_key, &data[24], 8);
+
+	skb_put(skb, sizeof(mgmt_frame->u.set_key) + FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function sends bootup parameters to the firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, corresponding error code on failure.
+ */
+static unsigned char rsi_load_bootup_params(struct rsi_common *common)
+{
+	struct sk_buff *skb;
+	struct rsi_mac_frame *mgmt_frame;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending boot params frame\n", __func__);
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s:\n", __func__);
+
+	if (common->channel_width == BW_40MHZ) {
+		memcpy(&mgmt_frame->u.bootup_params,
+		       &boot_params_40,
+		       sizeof(struct bootup_params));
+		rsi_dbg(MGMT_TX_ZONE, "%s: Packet 40MHZ <=== %d\n", __func__,
+			UMAC_CLK_40BW);
+		mgmt_frame->desc_word[7] = (UMAC_CLK_40BW);
+	} else {
+		memcpy(&mgmt_frame->u.bootup_params,
+		       &boot_params_20,
+		       sizeof(struct bootup_params));
+		if (boot_params_20.valid != VALID_20) {
+			mgmt_frame->desc_word[7] = (UMAC_CLK_20BW);
+			rsi_dbg(MGMT_TX_ZONE,
+				"%s: Packet 20MHZ <=== %d\n", __func__,
+				UMAC_CLK_20BW);
+		} else {
+			mgmt_frame->desc_word[7] = (UMAC_CLK_40MHZ);
+			rsi_dbg(MGMT_TX_ZONE,
+				"%s: Packet 20MHZ <=== %d\n", __func__,
+				UMAC_CLK_40MHZ);
+		}
+	}
+
+	/* Bit{0:11} indicates length of the Packet
+	 * Bit{12:15} indicates host queue number
+	 */
+	mgmt_frame->desc_word[0] = (sizeof(struct bootup_params) |
+				    (RSI_WIFI_MGMT_Q << 12));
+	mgmt_frame->desc_word[1] = (BOOTUP_PARAMS_REQUEST);
+
+	skb_put(skb, sizeof(struct bootup_params) + FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function prepares reset MAC request and sends a internal management
+ * frame to indicate it to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, corresponding error code on failure.
+ */
+static int rsi_send_reset_mac(struct rsi_common *common)
+{
+	struct sk_buff *skb;
+	struct rsi_mac_frame *mgmt_frame;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending reset MAC frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+	mgmt_frame->desc_word[1] = cpu_to_le16(RESET_MAC_REQ);
+	mgmt_frame->desc_word[4] |= cpu_to_le16(RETRY_COUNT << 8);
+
+	skb_put(skb, FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function programs the channel.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  channel Channel value to be set.
+ * @return 0 on success, corresponding error code on failure.
+ */
+int rsi_set_channel(struct rsi_common *common, unsigned short channel)
+{
+	struct sk_buff *skb = NULL;
+	struct rsi_mac_frame *mgmt_frame;
+
+	rsi_dbg(MGMT_TX_ZONE,
+		"%s: Sending scan req frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	if (common->band == IEEE80211_BAND_5GHZ) {
+		if ((channel >= 36) && (channel <= 64))
+			channel = ((channel - 32) / 4);
+		else if ((channel > 64) && (channel <= 140))
+			channel = ((channel - 102) / 4) + 8;
+		else if (channel >= 149)
+			channel = ((channel - 151) / 4) + 18;
+		else
+			return -1;
+	} else {
+		if (channel > 14) {
+			rsi_dbg(ERR_ZONE, "%s: Invalid chno %d, band = %d\n",
+				__func__, channel, common->band);
+			return 0;
+		}
+	}
+
+	mgmt_frame->desc_word[0] = ((sizeof(mgmt_frame->u.rf_prog_req)) |
+				    (RSI_WIFI_MGMT_Q << 12));
+	mgmt_frame->desc_word[1] = (SCAN_REQUEST);
+	mgmt_frame->desc_word[4] = channel;
+
+	mgmt_frame->desc_word[7] =  (PUT_BBP_RESET |
+				     BBP_REG_WRITE |
+				     (RSI_RF_TYPE << 4));
+
+
+	mgmt_frame->desc_word[4] = channel;
+	mgmt_frame->desc_word[5] = 0x01;
+
+	if (common->channel_width == BW_40MHZ)
+		mgmt_frame->desc_word[5] |= (0x1 << 8);
+
+	common->channel = channel;
+
+	skb_put(skb, sizeof(mgmt_frame->u.rf_prog_req) + FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function is used to compare two integers
+ *
+ * @param  pointer to the first integer
+ * @param  pointer to the second integer
+ * @return 0 if both are equal, -1 if the first is smaller, else 1
+ */
+static int rsi_compare(const void *a, const void *b)
+{
+	unsigned short int_a = *(const unsigned short *)(a);
+	unsigned short int_b = *(const unsigned short *)(b);
+
+	if (int_a > int_b)
+		return -1;
+
+	if (int_a < int_b)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * This function is used to map the selected rates to hw rates
+ *
+ * @param  the standard rate to be mapped
+ * @param  offset that will be returned
+ * @return 0 if it is a mcs rate, else 1
+ */
+static bool rsi_map_rates(unsigned short rate, int *offset)
+{
+	int kk;
+	for (kk = 0; kk < ARRAY_SIZE(rsi_mcsrates); kk++) {
+		if (rate == mcs[kk]) {
+			*offset = kk;
+			return 0;
+		}
+	}
+
+	for (kk = 0; kk < ARRAY_SIZE(rsi_rates); kk++) {
+		if (rate == rsi_rates[kk].bitrate/5) {
+			*offset = kk;
+			break;
+		}
+	}
+	return 1;
+}
+
+/**
+ * This function sets rates for connection ,sends autorate request.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, corresponding error code on failure.
+ */
+static int rsi_send_auto_rate_request(struct rsi_common *common)
+{
+	struct sk_buff *skb;
+	struct rsi_mac_frame *mgmt_frame;
+	int ii, jj, kk;
+	struct ieee80211_hw *hw = common->priv->hw;
+	unsigned char band = hw->conf.chandef.chan->band;
+	unsigned char num_supported_rates = 0;
+	unsigned char rate_offset = 0;
+	unsigned int rate_bitmap = common->bitrate_mask[band];
+
+	unsigned short *selected_rates, min_rate;
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	selected_rates = kmalloc(2 * RSI_TBL_SZ, GFP_KERNEL);
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	memset(selected_rates, 0, 2 * RSI_TBL_SZ);
+
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	mgmt_frame->u.auto_rate.aarf_rssi = cpu_to_le16(((
+					     (unsigned short)3 << 6) |
+					     (unsigned short)(18 & 0x3f)));
+	mgmt_frame->u.auto_rate.collision_tolerance = cpu_to_le16(3);
+	mgmt_frame->u.auto_rate.failure_limit = cpu_to_le16(3);
+	mgmt_frame->u.auto_rate.initial_boundary = cpu_to_le16(3);
+	mgmt_frame->u.auto_rate.max_threshold_limt = cpu_to_le16(27);
+
+	mgmt_frame->desc_word[1] = cpu_to_le16(AUTO_RATE_IND);
+
+	if (common->channel_width == BW_40MHZ)
+		mgmt_frame->desc_word[7] |= cpu_to_le16(1);
+
+	if (band == IEEE80211_BAND_2GHZ)
+		min_rate = STD_RATE_01;
+	else
+		min_rate = STD_RATE_06;
+
+	for (ii = 0, jj = 0; ii < ARRAY_SIZE(rsi_rates); ii++) {
+		if (rate_bitmap & BIT(ii)) {
+			selected_rates[jj++] = (rsi_rates[ii].bitrate / 5);
+			rate_offset++;
+		}
+	}
+	num_supported_rates = jj;
+
+	if (common->vif_info[0].is_ht) {
+		for (ii = 0; ii < ARRAY_SIZE(mcs); ii++)
+			selected_rates[jj++] = mcs[ii];
+		num_supported_rates += ARRAY_SIZE(mcs);
+		rate_offset += ARRAY_SIZE(mcs);
+	}
+
+	if (rate_offset < (RSI_TBL_SZ / 2) - 1) {
+		for (ii = jj; ii < (RSI_TBL_SZ / 2); ii++) {
+			selected_rates[jj++] = min_rate;
+			rate_offset++;
+		}
+	}
+
+	sort(selected_rates, jj, sizeof(unsigned short), &rsi_compare, NULL);
+
+	/* mapping the rates to RSI rates */
+	for (ii = 0; ii < jj; ii++) {
+		if (rsi_map_rates(selected_rates[ii], &kk)) {
+			mgmt_frame->u.auto_rate.supported_rates[ii] =
+				cpu_to_le16(rsi_rates[kk].hw_value);
+		} else {
+			mgmt_frame->u.auto_rate.supported_rates[ii] =
+				cpu_to_le16(rsi_mcsrates[kk]);
+		}
+	}
+
+	/* loading HT rates in the bottom half of the AR table */
+	if (common->vif_info[0].is_ht) {
+		if (common->vif_info[0].sgi)
+			mgmt_frame->u.auto_rate.supported_rates[rate_offset++] =
+				cpu_to_le16(RSI_RATE_MCS7_SG);
+
+		for (ii = rate_offset, kk = ARRAY_SIZE(rsi_mcsrates)-1;
+		     ii < rate_offset + 2*ARRAY_SIZE(rsi_mcsrates);
+		     ii++) {
+			if (common->vif_info[0].sgi)
+				mgmt_frame->u.auto_rate.supported_rates[ii++] =
+					cpu_to_le16(rsi_mcsrates[kk] | BIT(9));
+			mgmt_frame->u.auto_rate.supported_rates[ii] =
+				cpu_to_le16(rsi_mcsrates[kk--]);
+		}
+
+		for (; ii < RSI_TBL_SZ; ii++) {
+			mgmt_frame->u.auto_rate.supported_rates[ii] =
+				cpu_to_le16(rsi_mcsrates[0]);
+		}
+	}
+
+	mgmt_frame->u.auto_rate.num_supported_rates =
+		cpu_to_le16(num_supported_rates * 2);
+	mgmt_frame->u.auto_rate.moderate_rate_inx =
+		cpu_to_le16(num_supported_rates / 2);
+	mgmt_frame->desc_word[7] |= cpu_to_le16(0 << 8);
+	num_supported_rates *= 2;
+
+	mgmt_frame->desc_word[0] = cpu_to_le16((sizeof(mgmt_frame->u.auto_rate)
+				    + num_supported_rates +
+				    (RSI_WIFI_MGMT_Q << 12)));
+
+	skb_put(skb,
+		sizeof(mgmt_frame->u.auto_rate) + num_supported_rates +
+		       FRAME_DESC_SZ);
+	kfree(selected_rates);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function informs about bss status with the help of sta notify
+ * parameters by sending a internal management frame to firmware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  status Bss status type.
+ * @param  bssid Bssid.
+ * @param  qos_enable Qos is enabled.
+ * @param  aid Aid (unique for all STA).
+ * @return None.
+ */
+void rsi_inform_bss_status(struct rsi_common *common,
+			   unsigned char status,
+			   const unsigned char *bssid,
+			   unsigned char qos_enable,
+			   unsigned short aid)
+{
+	if (status) {
+		rsi_hal_send_sta_notify_frame(common,
+					      NL80211_IFTYPE_STATION,
+					      STA_CONNECTED,
+					      bssid,
+					      qos_enable,
+					      aid);
+		if (common->min_rate == 0xffff)
+			rsi_send_auto_rate_request(common);
+	} else {
+		rsi_hal_send_sta_notify_frame(common,
+					      NL80211_IFTYPE_STATION,
+					      STA_DISCONNECTED,
+					      bssid,
+					      qos_enable,
+					      aid);
+	}
+	return;
+}
+
+/**
+ * This function send a frame to read the
+ * mac address from the eeprom.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @return 0 on success, -1 on failure.
+ */
+static int rsi_eeprom_read(struct rsi_common *common)
+{
+	struct rsi_mac_frame *mgmt_frame;
+	struct sk_buff *skb;
+
+	rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__);
+
+	skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE);
+	if (!skb) {
+		rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n",
+			__func__);
+		return -1;
+	}
+
+	memset(skb->data, 0, MAX_MGMT_PKT_SIZE);
+	mgmt_frame = (struct rsi_mac_frame *)skb->data;
+
+	/* FrameType */
+	mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE);
+	mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12);
+	/* Number of bytes to read */
+	mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN +
+				    WLAN_MAC_MAGIC_WORD_LEN +
+				    WLAN_HOST_MODE_LEN);
+	/* Address to read */
+	mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR);
+
+	skb_put(skb, FRAME_DESC_SZ);
+
+	return rsi_send_internal_mgmt_frame(common, skb);
+}
+
+/**
+ * This function handles the confirm frames.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  msg Pointer to received packet.
+ * @return 0 on success, -1 on failure.
+ */
+static int rsi_handle_ta_confirm_type(struct rsi_common *common,
+				      unsigned char *msg)
+{
+	unsigned char sub_type = (msg[15] & 0xff);
+
+	switch (sub_type) {
+	case BOOTUP_PARAMS_REQUEST:
+		rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n",
+			__func__);
+		if (common->fsm_state == FSM_BOOT_PARAMS_SENT) {
+			if (rsi_eeprom_read(common)) {
+				common->fsm_state = FSM_CARD_NOT_READY;
+				goto out;
+			} else {
+				common->fsm_state = FSM_EEPROM_READ_MAC_ADDR;
+			}
+		} else {
+			rsi_dbg(ERR_ZONE,
+				"%s: Received bootup params cfm in %d state\n",
+				 __func__, common->fsm_state);
+			return 0;
+		}
+		break;
+
+	case EEPROM_READ_TYPE:
+		if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) {
+			if (msg[16] == MAGIC_WORD) {
+				memcpy(common->mac_addr,
+				       &msg[FRAME_DESC_SZ +
+				       WLAN_HOST_MODE_LEN +
+				       WLAN_MAC_MAGIC_WORD_LEN],
+				       ETH_ALEN);
+			} else {
+				common->fsm_state = FSM_CARD_NOT_READY;
+				break;
+			}
+			if (rsi_send_reset_mac(common))
+				goto out;
+			else
+				common->fsm_state = FSM_RESET_MAC_SENT;
+		} else {
+			rsi_dbg(ERR_ZONE,
+				"%s: Received eeprom mac addr in %d state\n",
+				__func__, common->fsm_state);
+			return 0;
+		}
+		break;
+
+	case RESET_MAC_REQ:
+		if (common->fsm_state == FSM_RESET_MAC_SENT) {
+			rsi_dbg(FSM_ZONE, "%s: Reset MAC cfm received\n",
+				__func__);
+
+			if (rsi_load_radio_caps(common))
+				goto out;
+			else
+				common->fsm_state = FSM_RADIO_CAPS_SENT;
+		} else {
+			rsi_dbg(ERR_ZONE,
+				"%s: Received reset mac cfm in %d state\n",
+				 __func__, common->fsm_state);
+			return 0;
+		}
+		break;
+
+	case RADIO_CAPABILITIES:
+		if (common->fsm_state == FSM_RADIO_CAPS_SENT) {
+			common->rf_reset = 1;
+			if (rsi_program_bb_rf(common)) {
+				goto out;
+			} else {
+				common->fsm_state = FSM_BB_RF_PROG_SENT;
+				rsi_dbg(FSM_ZONE, "%s: Radio cap cfm received\n",
+					__func__);
+			}
+		} else {
+			rsi_dbg(ERR_ZONE,
+				"%s: Received radio caps cfm in %d state\n",
+				 __func__, common->fsm_state);
+			return 0;
+		}
+		break;
+
+	case BB_PROG_VALUES_REQUEST:
+	case RF_PROG_VALUES_REQUEST:
+	case BBP_PROG_IN_TA:
+		rsi_dbg(FSM_ZONE, "%s: BB/RF cfm received\n", __func__);
+		if (common->fsm_state == FSM_BB_RF_PROG_SENT) {
+			common->bb_rf_prog_count--;
+			if (!common->bb_rf_prog_count) {
+				common->fsm_state = FSM_MAC_INIT_DONE;
+				return rsi_mac80211_attach(common);
+			}
+		} else {
+			goto out;
+		}
+		break;
+
+	default:
+		rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n",
+			__func__);
+		break;
+	}
+	return 0;
+out:
+	rsi_dbg(ERR_ZONE, "%s: Unable to send pkt/Invalid frame received\n",
+		__func__);
+	return -1;
+}
+
+/**
+ * This function process the management packets recieved from the hardware.
+ *
+ * @param  common Pointer to the driver private structure.
+ * @param  msg Pointer to the received packet.
+ * @return 0 on success, -1 on failure.
+ */
+int rsi_mgmt_pkt_recv(struct rsi_common *common, unsigned char *msg)
+{
+	int msg_len = (*(unsigned short *)&msg[0] & 0x0fff);
+	unsigned short msg_type = (msg[2]);
+
+	rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n",
+		__func__, msg_len, msg_type);
+
+	if (msg_type == TA_CONFIRM_TYPE) {
+		return rsi_handle_ta_confirm_type(common, msg);
+	} else if (msg_type == CARD_READY_IND) {
+		rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n",
+			__func__);
+		if (common->fsm_state == FSM_CARD_NOT_READY) {
+			if (rsi_load_bootup_params(common))
+				return -1;
+			else
+				common->fsm_state = FSM_BOOT_PARAMS_SENT;
+		} else {
+			return -1;
+		}
+	} else if (msg_type == TX_STATUS_IND) {
+		if (msg[15] == PROBEREQ_CONFIRM)
+			common->mgmt_q_block = false;
+			rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n",
+				__func__);
+	} else {
+		return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type);
+	}
+	return 0;
+}