xref: /linux/drivers/net/wireless/rsi/rsi_91x_hal.c (revision 353b7a55dcaf5fb8758e09ebe2ddf5f3adbac7c5)
19463fd55SLee Jones /*
2dad0d04fSFariya Fatima  * Copyright (c) 2014 Redpine Signals Inc.
3dad0d04fSFariya Fatima  *
4dad0d04fSFariya Fatima  * Permission to use, copy, modify, and/or distribute this software for any
5dad0d04fSFariya Fatima  * purpose with or without fee is hereby granted, provided that the above
6dad0d04fSFariya Fatima  * copyright notice and this permission notice appear in all copies.
7dad0d04fSFariya Fatima  *
8dad0d04fSFariya Fatima  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9dad0d04fSFariya Fatima  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10dad0d04fSFariya Fatima  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11dad0d04fSFariya Fatima  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12dad0d04fSFariya Fatima  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13dad0d04fSFariya Fatima  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14dad0d04fSFariya Fatima  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15dad0d04fSFariya Fatima  */
16dad0d04fSFariya Fatima 
17b78e91bcSPrameela Rani Garnepudi #include <linux/firmware.h>
18716b840cSSiva Rebbagondla #include <net/bluetooth/bluetooth.h>
19dad0d04fSFariya Fatima #include "rsi_mgmt.h"
20b78e91bcSPrameela Rani Garnepudi #include "rsi_hal.h"
21b78e91bcSPrameela Rani Garnepudi #include "rsi_sdio.h"
2219844c0aSPrameela Rani Garnepudi #include "rsi_common.h"
23b78e91bcSPrameela Rani Garnepudi 
24b78e91bcSPrameela Rani Garnepudi /* FLASH Firmware */
25b78e91bcSPrameela Rani Garnepudi static struct ta_metadata metadata_flash_content[] = {
26b78e91bcSPrameela Rani Garnepudi 	{"flash_content", 0x00010000},
27219569adSamit karwar 	{"rsi/rs9113_wlan_qspi.rps", 0x00010000},
28716b840cSSiva Rebbagondla 	{"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
29f5fbce65SSiva Rebbagondla 	{"flash_content", 0x00010000},
30f5fbce65SSiva Rebbagondla 	{"rsi/rs9113_ap_bt_dual_mode.rps", 0x00010000},
31f5fbce65SSiva Rebbagondla 
32b78e91bcSPrameela Rani Garnepudi };
33dad0d04fSFariya Fatima 
34e5a1ecc9SSiva Rebbagondla static struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000},
35e5a1ecc9SSiva Rebbagondla 	{"rsi/rs9116_wlan.rps", 0x00000000},
36e5a1ecc9SSiva Rebbagondla 	{"rsi/rs9116_wlan_bt_classic.rps", 0x00000000},
37e5a1ecc9SSiva Rebbagondla 	{"rsi/pmemdata_dummy", 0x00000000},
38e5a1ecc9SSiva Rebbagondla 	{"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}
39e5a1ecc9SSiva Rebbagondla };
40e5a1ecc9SSiva Rebbagondla 
41d26a9559SPrameela Rani Garnepudi int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
42d26a9559SPrameela Rani Garnepudi {
43d26a9559SPrameela Rani Garnepudi 	struct rsi_hw *adapter = common->priv;
44d26a9559SPrameela Rani Garnepudi 	int status;
45d26a9559SPrameela Rani Garnepudi 
462108df3cSPrameela Rani Garnepudi 	if (common->coex_mode > 1)
472108df3cSPrameela Rani Garnepudi 		mutex_lock(&common->tx_bus_mutex);
482108df3cSPrameela Rani Garnepudi 
49d26a9559SPrameela Rani Garnepudi 	status = adapter->host_intf_ops->write_pkt(common->priv,
50d26a9559SPrameela Rani Garnepudi 						   skb->data, skb->len);
512108df3cSPrameela Rani Garnepudi 
522108df3cSPrameela Rani Garnepudi 	if (common->coex_mode > 1)
532108df3cSPrameela Rani Garnepudi 		mutex_unlock(&common->tx_bus_mutex);
542108df3cSPrameela Rani Garnepudi 
55d26a9559SPrameela Rani Garnepudi 	return status;
56d26a9559SPrameela Rani Garnepudi }
576507de6dSPrameela Rani Garnepudi 
581be05eb5SPrameela Rani Garnepudi int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
596507de6dSPrameela Rani Garnepudi {
606507de6dSPrameela Rani Garnepudi 	struct rsi_hw *adapter = common->priv;
616507de6dSPrameela Rani Garnepudi 	struct ieee80211_hdr *wh = NULL;
626507de6dSPrameela Rani Garnepudi 	struct ieee80211_tx_info *info;
636507de6dSPrameela Rani Garnepudi 	struct ieee80211_conf *conf = &adapter->hw->conf;
644671c209SPrameela Rani Garnepudi 	struct ieee80211_vif *vif;
656507de6dSPrameela Rani Garnepudi 	struct rsi_mgmt_desc *mgmt_desc;
666507de6dSPrameela Rani Garnepudi 	struct skb_info *tx_params;
675dc36387SPrameela Rani Garnepudi 	struct rsi_xtended_desc *xtend_desc = NULL;
686507de6dSPrameela Rani Garnepudi 	u8 header_size;
696507de6dSPrameela Rani Garnepudi 	u32 dword_align_bytes = 0;
706507de6dSPrameela Rani Garnepudi 
7119844c0aSPrameela Rani Garnepudi 	if (skb->len > MAX_MGMT_PKT_SIZE) {
7219844c0aSPrameela Rani Garnepudi 		rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
7319844c0aSPrameela Rani Garnepudi 		return -EINVAL;
7419844c0aSPrameela Rani Garnepudi 	}
7519844c0aSPrameela Rani Garnepudi 
766507de6dSPrameela Rani Garnepudi 	info = IEEE80211_SKB_CB(skb);
776507de6dSPrameela Rani Garnepudi 	tx_params = (struct skb_info *)info->driver_data;
784671c209SPrameela Rani Garnepudi 	vif = tx_params->vif;
796507de6dSPrameela Rani Garnepudi 
806507de6dSPrameela Rani Garnepudi 	/* Update header size */
815dc36387SPrameela Rani Garnepudi 	header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc);
826507de6dSPrameela Rani Garnepudi 	if (header_size > skb_headroom(skb)) {
836507de6dSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
846507de6dSPrameela Rani Garnepudi 			"%s: Failed to add extended descriptor\n",
856507de6dSPrameela Rani Garnepudi 			__func__);
866507de6dSPrameela Rani Garnepudi 		return -ENOSPC;
876507de6dSPrameela Rani Garnepudi 	}
886507de6dSPrameela Rani Garnepudi 	skb_push(skb, header_size);
896507de6dSPrameela Rani Garnepudi 	dword_align_bytes = ((unsigned long)skb->data & 0x3f);
906507de6dSPrameela Rani Garnepudi 	if (dword_align_bytes > skb_headroom(skb)) {
916507de6dSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
926507de6dSPrameela Rani Garnepudi 			"%s: Failed to add dword align\n", __func__);
936507de6dSPrameela Rani Garnepudi 		return -ENOSPC;
946507de6dSPrameela Rani Garnepudi 	}
956507de6dSPrameela Rani Garnepudi 	skb_push(skb, dword_align_bytes);
966507de6dSPrameela Rani Garnepudi 	header_size += dword_align_bytes;
976507de6dSPrameela Rani Garnepudi 
986507de6dSPrameela Rani Garnepudi 	tx_params->internal_hdr_size = header_size;
996507de6dSPrameela Rani Garnepudi 	memset(&skb->data[0], 0, header_size);
1006507de6dSPrameela Rani Garnepudi 	wh = (struct ieee80211_hdr *)&skb->data[header_size];
1016507de6dSPrameela Rani Garnepudi 
1026507de6dSPrameela Rani Garnepudi 	mgmt_desc = (struct rsi_mgmt_desc *)skb->data;
1035dc36387SPrameela Rani Garnepudi 	xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
1046507de6dSPrameela Rani Garnepudi 
1056507de6dSPrameela Rani Garnepudi 	rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
1066507de6dSPrameela Rani Garnepudi 			RSI_WIFI_MGMT_Q);
1076507de6dSPrameela Rani Garnepudi 	mgmt_desc->frame_type = TX_DOT11_MGMT;
1086507de6dSPrameela Rani Garnepudi 	mgmt_desc->header_len = MIN_802_11_HDR_LEN;
1096507de6dSPrameela Rani Garnepudi 	mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;
1107fdcb8e1SPrameela Rani Garnepudi 
1117fdcb8e1SPrameela Rani Garnepudi 	if (ieee80211_is_probe_req(wh->frame_control))
1127fdcb8e1SPrameela Rani Garnepudi 		mgmt_desc->frame_info = cpu_to_le16(RSI_INSERT_SEQ_IN_FW);
1136507de6dSPrameela Rani Garnepudi 	mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE);
1146507de6dSPrameela Rani Garnepudi 	if (is_broadcast_ether_addr(wh->addr1))
1156507de6dSPrameela Rani Garnepudi 		mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT);
1166507de6dSPrameela Rani Garnepudi 
1176507de6dSPrameela Rani Garnepudi 	mgmt_desc->seq_ctrl =
1186507de6dSPrameela Rani Garnepudi 		cpu_to_le16(IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)));
1194671c209SPrameela Rani Garnepudi 	if ((common->band == NL80211_BAND_2GHZ) && !common->p2p_enabled)
1204671c209SPrameela Rani Garnepudi 		mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_1);
1216507de6dSPrameela Rani Garnepudi 	else
1224671c209SPrameela Rani Garnepudi 		mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_6);
1236507de6dSPrameela Rani Garnepudi 
1246507de6dSPrameela Rani Garnepudi 	if (conf_is_ht40(conf))
1256507de6dSPrameela Rani Garnepudi 		mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
1266507de6dSPrameela Rani Garnepudi 
12719844c0aSPrameela Rani Garnepudi 	if (ieee80211_is_probe_resp(wh->frame_control)) {
12819844c0aSPrameela Rani Garnepudi 		mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID |
12919844c0aSPrameela Rani Garnepudi 					  RSI_FETCH_RETRY_CNT_FRM_HST);
13019844c0aSPrameela Rani Garnepudi #define PROBE_RESP_RETRY_CNT	3
13119844c0aSPrameela Rani Garnepudi 		xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT;
13219844c0aSPrameela Rani Garnepudi 	}
13319844c0aSPrameela Rani Garnepudi 
1344671c209SPrameela Rani Garnepudi 	if (((vif->type == NL80211_IFTYPE_AP) ||
1354671c209SPrameela Rani Garnepudi 	     (vif->type == NL80211_IFTYPE_P2P_GO)) &&
13619844c0aSPrameela Rani Garnepudi 	    (ieee80211_is_action(wh->frame_control))) {
13719844c0aSPrameela Rani Garnepudi 		struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1);
13819844c0aSPrameela Rani Garnepudi 
13919844c0aSPrameela Rani Garnepudi 		if (rsta)
14019844c0aSPrameela Rani Garnepudi 			mgmt_desc->sta_id = tx_params->sta_id;
14119844c0aSPrameela Rani Garnepudi 		else
14219844c0aSPrameela Rani Garnepudi 			return -EINVAL;
14319844c0aSPrameela Rani Garnepudi 	}
1444671c209SPrameela Rani Garnepudi 	mgmt_desc->rate_info |=
1454671c209SPrameela Rani Garnepudi 		cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) &
1464671c209SPrameela Rani Garnepudi 			    RSI_DESC_VAP_ID_MASK);
1474671c209SPrameela Rani Garnepudi 
1486507de6dSPrameela Rani Garnepudi 	return 0;
1496507de6dSPrameela Rani Garnepudi }
1506507de6dSPrameela Rani Garnepudi 
151ceb2e4eaSPavani Muthyala /* This function prepares descriptor for given data packet */
1521be05eb5SPrameela Rani Garnepudi int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
153dad0d04fSFariya Fatima {
154ce86893fSKarun Eagalapati 	struct rsi_hw *adapter = common->priv;
155ce86893fSKarun Eagalapati 	struct ieee80211_vif *vif;
1560eb42586SPavani Muthyala 	struct ieee80211_hdr *wh = NULL;
157dad0d04fSFariya Fatima 	struct ieee80211_tx_info *info;
158dad0d04fSFariya Fatima 	struct skb_info *tx_params;
159af193097SPavani Muthyala 	struct rsi_data_desc *data_desc;
1605dc36387SPrameela Rani Garnepudi 	struct rsi_xtended_desc *xtend_desc;
161dad0d04fSFariya Fatima 	u8 ieee80211_size = MIN_802_11_HDR_LEN;
1620eb42586SPavani Muthyala 	u8 header_size;
1630eb42586SPavani Muthyala 	u8 vap_id = 0;
1640eb42586SPavani Muthyala 	u8 dword_align_bytes;
165ab2ef1d6SMarkus Elfring 	u16 seq_num;
166dad0d04fSFariya Fatima 
167dad0d04fSFariya Fatima 	info = IEEE80211_SKB_CB(skb);
168eac4eed3SPrameela Rani Garnepudi 	vif = info->control.vif;
169dad0d04fSFariya Fatima 	tx_params = (struct skb_info *)info->driver_data;
170dad0d04fSFariya Fatima 
1715dc36387SPrameela Rani Garnepudi 	header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc);
1720eb42586SPavani Muthyala 	if (header_size > skb_headroom(skb)) {
173dad0d04fSFariya Fatima 		rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
174ceb2e4eaSPavani Muthyala 		return -ENOSPC;
175dad0d04fSFariya Fatima 	}
1760eb42586SPavani Muthyala 	skb_push(skb, header_size);
1770eb42586SPavani Muthyala 	dword_align_bytes = ((unsigned long)skb->data & 0x3f);
1780eb42586SPavani Muthyala 	if (header_size > skb_headroom(skb)) {
1790eb42586SPavani Muthyala 		rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
180ceb2e4eaSPavani Muthyala 		return -ENOSPC;
1810eb42586SPavani Muthyala 	}
1820eb42586SPavani Muthyala 	skb_push(skb, dword_align_bytes);
1830eb42586SPavani Muthyala 	header_size += dword_align_bytes;
184dad0d04fSFariya Fatima 
1850eb42586SPavani Muthyala 	tx_params->internal_hdr_size = header_size;
186af193097SPavani Muthyala 	data_desc = (struct rsi_data_desc *)skb->data;
1870eb42586SPavani Muthyala 	memset(data_desc, 0, header_size);
188dad0d04fSFariya Fatima 
1895dc36387SPrameela Rani Garnepudi 	xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
1900eb42586SPavani Muthyala 	wh = (struct ieee80211_hdr *)&skb->data[header_size];
19119844c0aSPrameela Rani Garnepudi 	seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl));
1920eb42586SPavani Muthyala 
1930eb42586SPavani Muthyala 	data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;
1940eb42586SPavani Muthyala 
1950eb42586SPavani Muthyala 	if (ieee80211_is_data_qos(wh->frame_control)) {
196dad0d04fSFariya Fatima 		ieee80211_size += 2;
197af193097SPavani Muthyala 		data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE);
198dad0d04fSFariya Fatima 	}
199dad0d04fSFariya Fatima 
200eac4eed3SPrameela Rani Garnepudi 	if (((vif->type == NL80211_IFTYPE_STATION) ||
201eac4eed3SPrameela Rani Garnepudi 	     (vif->type == NL80211_IFTYPE_P2P_CLIENT)) &&
202ce86893fSKarun Eagalapati 	    (adapter->ps_state == PS_ENABLED))
203ce86893fSKarun Eagalapati 		wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
204ce86893fSKarun Eagalapati 
205dad0d04fSFariya Fatima 	if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
206*31453804SMartin Fuzzey 	    info->control.hw_key) {
207dad0d04fSFariya Fatima 		if (rsi_is_cipher_wep(common))
208dad0d04fSFariya Fatima 			ieee80211_size += 4;
209dad0d04fSFariya Fatima 		else
210dad0d04fSFariya Fatima 			ieee80211_size += 8;
211af193097SPavani Muthyala 		data_desc->mac_flags |= cpu_to_le16(RSI_ENCRYPT_PKT);
212dad0d04fSFariya Fatima 	}
213af193097SPavani Muthyala 	rsi_set_len_qno(&data_desc->len_qno, (skb->len - FRAME_DESC_SZ),
214af193097SPavani Muthyala 			RSI_WIFI_DATA_Q);
215af193097SPavani Muthyala 	data_desc->header_len = ieee80211_size;
216dad0d04fSFariya Fatima 
217af193097SPavani Muthyala 	if (common->min_rate != RSI_RATE_AUTO) {
218dad0d04fSFariya Fatima 		/* Send fixed rate */
219af193097SPavani Muthyala 		data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
220af193097SPavani Muthyala 		data_desc->rate_info = cpu_to_le16(common->min_rate);
221e8c58e7aSJahnavi Meher 
222e8c58e7aSJahnavi Meher 		if (conf_is_ht40(&common->priv->hw->conf))
223af193097SPavani Muthyala 			data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
224e8c58e7aSJahnavi Meher 
22519844c0aSPrameela Rani Garnepudi 		if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) {
22619844c0aSPrameela Rani Garnepudi 		       /* Only MCS rates */
227af193097SPavani Muthyala 			data_desc->rate_info |=
2282bfa6969SJahnavi Meher 				cpu_to_le16(ENABLE_SHORTGI_RATE);
2292bfa6969SJahnavi Meher 		}
2300eb42586SPavani Muthyala 	}
2310eb42586SPavani Muthyala 
2320eb42586SPavani Muthyala 	if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
2330eb42586SPavani Muthyala 		rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n");
2340eb42586SPavani Muthyala 
2350eb42586SPavani Muthyala 		data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
2360eb42586SPavani Muthyala 		if (common->band == NL80211_BAND_5GHZ)
2370eb42586SPavani Muthyala 			data_desc->rate_info = cpu_to_le16(RSI_RATE_6);
2380eb42586SPavani Muthyala 		else
2390eb42586SPavani Muthyala 			data_desc->rate_info = cpu_to_le16(RSI_RATE_1);
2400eb42586SPavani Muthyala 		data_desc->mac_flags |= cpu_to_le16(RSI_REKEY_PURPOSE);
2410eb42586SPavani Muthyala 		data_desc->misc_flags |= RSI_FETCH_RETRY_CNT_FRM_HST;
2420eb42586SPavani Muthyala #define EAPOL_RETRY_CNT 15
2430eb42586SPavani Muthyala 		xtend_desc->retry_cnt = EAPOL_RETRY_CNT;
2444fd6c476SPrameela Rani Garnepudi 
2454fd6c476SPrameela Rani Garnepudi 		if (common->eapol4_confirm)
2464fd6c476SPrameela Rani Garnepudi 			skb->priority = VO_Q;
2474fd6c476SPrameela Rani Garnepudi 		else
2484fd6c476SPrameela Rani Garnepudi 			rsi_set_len_qno(&data_desc->len_qno,
2494fd6c476SPrameela Rani Garnepudi 					(skb->len - FRAME_DESC_SZ),
2504fd6c476SPrameela Rani Garnepudi 					RSI_WIFI_MGMT_Q);
25165277100SMarek Vasut 		if (((skb->len - header_size) == EAPOL4_PACKET_LEN) ||
25265277100SMarek Vasut 		    ((skb->len - header_size) == EAPOL4_PACKET_LEN - 2)) {
2534fd6c476SPrameela Rani Garnepudi 			data_desc->misc_flags |=
2544fd6c476SPrameela Rani Garnepudi 				RSI_DESC_REQUIRE_CFM_TO_HOST;
2554fd6c476SPrameela Rani Garnepudi 			xtend_desc->confirm_frame_type = EAPOL4_CONFIRM;
2564fd6c476SPrameela Rani Garnepudi 		}
257dad0d04fSFariya Fatima 	}
258dad0d04fSFariya Fatima 
25992e97123SSiva Rebbagondla 	data_desc->mac_flags |= cpu_to_le16(seq_num & 0xfff);
260af193097SPavani Muthyala 	data_desc->qid_tid = ((skb->priority & 0xf) |
261af193097SPavani Muthyala 			      ((tx_params->tid & 0xf) << 4));
262af193097SPavani Muthyala 	data_desc->sta_id = tx_params->sta_id;
263dad0d04fSFariya Fatima 
2640eb42586SPavani Muthyala 	if ((is_broadcast_ether_addr(wh->addr1)) ||
2650eb42586SPavani Muthyala 	    (is_multicast_ether_addr(wh->addr1))) {
2660eb42586SPavani Muthyala 		data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
2670eb42586SPavani Muthyala 		data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT);
2680eb42586SPavani Muthyala 		data_desc->sta_id = vap_id;
26919844c0aSPrameela Rani Garnepudi 
270eac4eed3SPrameela Rani Garnepudi 		if ((vif->type == NL80211_IFTYPE_AP) ||
271eac4eed3SPrameela Rani Garnepudi 		    (vif->type == NL80211_IFTYPE_P2P_GO)) {
27219844c0aSPrameela Rani Garnepudi 			if (common->band == NL80211_BAND_5GHZ)
27319844c0aSPrameela Rani Garnepudi 				data_desc->rate_info = cpu_to_le16(RSI_RATE_6);
27419844c0aSPrameela Rani Garnepudi 			else
27519844c0aSPrameela Rani Garnepudi 				data_desc->rate_info = cpu_to_le16(RSI_RATE_1);
2760eb42586SPavani Muthyala 		}
27719844c0aSPrameela Rani Garnepudi 	}
278eac4eed3SPrameela Rani Garnepudi 	if (((vif->type == NL80211_IFTYPE_AP) ||
279eac4eed3SPrameela Rani Garnepudi 	     (vif->type == NL80211_IFTYPE_P2P_GO)) &&
28019844c0aSPrameela Rani Garnepudi 	    (ieee80211_has_moredata(wh->frame_control)))
28119844c0aSPrameela Rani Garnepudi 		data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT);
2820eb42586SPavani Muthyala 
283eac4eed3SPrameela Rani Garnepudi 	data_desc->rate_info |=
284eac4eed3SPrameela Rani Garnepudi 		cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) &
285eac4eed3SPrameela Rani Garnepudi 			    RSI_DESC_VAP_ID_MASK);
286eac4eed3SPrameela Rani Garnepudi 
287ceb2e4eaSPavani Muthyala 	return 0;
288ceb2e4eaSPavani Muthyala }
289ceb2e4eaSPavani Muthyala 
290ceb2e4eaSPavani Muthyala /* This function sends received data packet from driver to device */
291ceb2e4eaSPavani Muthyala int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
292ceb2e4eaSPavani Muthyala {
293ceb2e4eaSPavani Muthyala 	struct rsi_hw *adapter = common->priv;
294eac4eed3SPrameela Rani Garnepudi 	struct ieee80211_vif *vif;
295ceb2e4eaSPavani Muthyala 	struct ieee80211_tx_info *info;
296ceb2e4eaSPavani Muthyala 	struct ieee80211_bss_conf *bss;
29719844c0aSPrameela Rani Garnepudi 	int status = -EINVAL;
29819844c0aSPrameela Rani Garnepudi 
29919844c0aSPrameela Rani Garnepudi 	if (!skb)
30019844c0aSPrameela Rani Garnepudi 		return 0;
30119844c0aSPrameela Rani Garnepudi 	if (common->iface_down)
30219844c0aSPrameela Rani Garnepudi 		goto err;
303ceb2e4eaSPavani Muthyala 
304ceb2e4eaSPavani Muthyala 	info = IEEE80211_SKB_CB(skb);
30519844c0aSPrameela Rani Garnepudi 	if (!info->control.vif)
30619844c0aSPrameela Rani Garnepudi 		goto err;
307eac4eed3SPrameela Rani Garnepudi 	vif = info->control.vif;
308eac4eed3SPrameela Rani Garnepudi 	bss = &vif->bss_conf;
309ceb2e4eaSPavani Muthyala 
310eac4eed3SPrameela Rani Garnepudi 	if (((vif->type == NL80211_IFTYPE_STATION) ||
311eac4eed3SPrameela Rani Garnepudi 	     (vif->type == NL80211_IFTYPE_P2P_CLIENT)) &&
312eac4eed3SPrameela Rani Garnepudi 	    (!bss->assoc))
313ceb2e4eaSPavani Muthyala 		goto err;
314ceb2e4eaSPavani Muthyala 
3152108df3cSPrameela Rani Garnepudi 	status = rsi_send_pkt_to_bus(common, skb);
316dad0d04fSFariya Fatima 	if (status)
317ceb2e4eaSPavani Muthyala 		rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
318dad0d04fSFariya Fatima 
319dad0d04fSFariya Fatima err:
320dad0d04fSFariya Fatima 	++common->tx_stats.total_tx_pkt_freed[skb->priority];
321af193097SPavani Muthyala 	rsi_indicate_tx_status(adapter, skb, status);
322dad0d04fSFariya Fatima 	return status;
323dad0d04fSFariya Fatima }
324dad0d04fSFariya Fatima 
325dad0d04fSFariya Fatima /**
326dad0d04fSFariya Fatima  * rsi_send_mgmt_pkt() - This functions sends the received management packet
327dad0d04fSFariya Fatima  *			 from driver to device.
328dad0d04fSFariya Fatima  * @common: Pointer to the driver private structure.
329dad0d04fSFariya Fatima  * @skb: Pointer to the socket buffer structure.
330dad0d04fSFariya Fatima  *
331dad0d04fSFariya Fatima  * Return: status: 0 on success, -1 on failure.
332dad0d04fSFariya Fatima  */
333dad0d04fSFariya Fatima int rsi_send_mgmt_pkt(struct rsi_common *common,
334dad0d04fSFariya Fatima 		      struct sk_buff *skb)
335dad0d04fSFariya Fatima {
336dad0d04fSFariya Fatima 	struct rsi_hw *adapter = common->priv;
3371be05eb5SPrameela Rani Garnepudi 	struct ieee80211_bss_conf *bss;
3381be05eb5SPrameela Rani Garnepudi 	struct ieee80211_hdr *wh;
339dad0d04fSFariya Fatima 	struct ieee80211_tx_info *info;
340dad0d04fSFariya Fatima 	struct skb_info *tx_params;
3411be05eb5SPrameela Rani Garnepudi 	struct rsi_mgmt_desc *mgmt_desc;
3421be05eb5SPrameela Rani Garnepudi 	struct rsi_xtended_desc *xtend_desc;
343dad0d04fSFariya Fatima 	int status = -E2BIG;
3441be05eb5SPrameela Rani Garnepudi 	u8 header_size;
345dad0d04fSFariya Fatima 
346dad0d04fSFariya Fatima 	info = IEEE80211_SKB_CB(skb);
347dad0d04fSFariya Fatima 	tx_params = (struct skb_info *)info->driver_data;
3481be05eb5SPrameela Rani Garnepudi 	header_size = tx_params->internal_hdr_size;
349dad0d04fSFariya Fatima 
350dad0d04fSFariya Fatima 	if (tx_params->flags & INTERNAL_MGMT_PKT) {
351a2ce952cSPrameela Rani Garnepudi 		status = adapter->host_intf_ops->write_pkt(common->priv,
352dad0d04fSFariya Fatima 							   (u8 *)skb->data,
353dad0d04fSFariya Fatima 							   skb->len);
354dad0d04fSFariya Fatima 		if (status) {
355dad0d04fSFariya Fatima 			rsi_dbg(ERR_ZONE,
356dad0d04fSFariya Fatima 				"%s: Failed to write the packet\n", __func__);
357dad0d04fSFariya Fatima 		}
358dad0d04fSFariya Fatima 		dev_kfree_skb(skb);
359dad0d04fSFariya Fatima 		return status;
360dad0d04fSFariya Fatima 	}
361dad0d04fSFariya Fatima 
3621be05eb5SPrameela Rani Garnepudi 	bss = &info->control.vif->bss_conf;
3631be05eb5SPrameela Rani Garnepudi 	wh = (struct ieee80211_hdr *)&skb->data[header_size];
3641be05eb5SPrameela Rani Garnepudi 	mgmt_desc = (struct rsi_mgmt_desc *)skb->data;
3651be05eb5SPrameela Rani Garnepudi 	xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
366dad0d04fSFariya Fatima 
3671be05eb5SPrameela Rani Garnepudi 	/* Indicate to firmware to give cfm for probe */
3681be05eb5SPrameela Rani Garnepudi 	if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) {
3691be05eb5SPrameela Rani Garnepudi 		rsi_dbg(INFO_ZONE,
3701be05eb5SPrameela Rani Garnepudi 			"%s: blocking mgmt queue\n", __func__);
3711be05eb5SPrameela Rani Garnepudi 		mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST;
3721be05eb5SPrameela Rani Garnepudi 		xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM;
3731be05eb5SPrameela Rani Garnepudi 		common->mgmt_q_block = true;
3741be05eb5SPrameela Rani Garnepudi 		rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n");
3751be05eb5SPrameela Rani Garnepudi 	}
3761be05eb5SPrameela Rani Garnepudi 
3772108df3cSPrameela Rani Garnepudi 	status = rsi_send_pkt_to_bus(common, skb);
378dad0d04fSFariya Fatima 	if (status)
379dad0d04fSFariya Fatima 		rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
380dad0d04fSFariya Fatima 
381dad0d04fSFariya Fatima 	rsi_indicate_tx_status(common->priv, skb, status);
382dad0d04fSFariya Fatima 	return status;
383dad0d04fSFariya Fatima }
384b78e91bcSPrameela Rani Garnepudi 
385716b840cSSiva Rebbagondla int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
386716b840cSSiva Rebbagondla {
387716b840cSSiva Rebbagondla 	int status = -EINVAL;
388716b840cSSiva Rebbagondla 	u8 header_size = 0;
389716b840cSSiva Rebbagondla 	struct rsi_bt_desc *bt_desc;
390716b840cSSiva Rebbagondla 	u8 queueno = ((skb->data[1] >> 4) & 0xf);
391716b840cSSiva Rebbagondla 
392716b840cSSiva Rebbagondla 	if (queueno == RSI_BT_MGMT_Q) {
393716b840cSSiva Rebbagondla 		status = rsi_send_pkt_to_bus(common, skb);
394716b840cSSiva Rebbagondla 		if (status)
395716b840cSSiva Rebbagondla 			rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
396716b840cSSiva Rebbagondla 				__func__);
397716b840cSSiva Rebbagondla 		goto out;
398716b840cSSiva Rebbagondla 	}
399716b840cSSiva Rebbagondla 	header_size = FRAME_DESC_SZ;
400716b840cSSiva Rebbagondla 	if (header_size > skb_headroom(skb)) {
401716b840cSSiva Rebbagondla 		rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
402716b840cSSiva Rebbagondla 		status = -ENOSPC;
403716b840cSSiva Rebbagondla 		goto out;
404716b840cSSiva Rebbagondla 	}
405716b840cSSiva Rebbagondla 	skb_push(skb, header_size);
406716b840cSSiva Rebbagondla 	memset(skb->data, 0, header_size);
407716b840cSSiva Rebbagondla 	bt_desc = (struct rsi_bt_desc *)skb->data;
408716b840cSSiva Rebbagondla 
409716b840cSSiva Rebbagondla 	rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
410716b840cSSiva Rebbagondla 			RSI_BT_DATA_Q);
411716b840cSSiva Rebbagondla 	bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
412716b840cSSiva Rebbagondla 
413716b840cSSiva Rebbagondla 	status = rsi_send_pkt_to_bus(common, skb);
414716b840cSSiva Rebbagondla 	if (status)
415716b840cSSiva Rebbagondla 		rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
416716b840cSSiva Rebbagondla 
417716b840cSSiva Rebbagondla out:
418716b840cSSiva Rebbagondla 	dev_kfree_skb(skb);
419716b840cSSiva Rebbagondla 	return status;
420716b840cSSiva Rebbagondla }
421716b840cSSiva Rebbagondla 
422d26a9559SPrameela Rani Garnepudi int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
423d26a9559SPrameela Rani Garnepudi {
424d26a9559SPrameela Rani Garnepudi 	struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
425d26a9559SPrameela Rani Garnepudi 	struct rsi_data_desc *bcn_frm;
426d26a9559SPrameela Rani Garnepudi 	struct ieee80211_hw *hw = common->priv->hw;
427d26a9559SPrameela Rani Garnepudi 	struct ieee80211_conf *conf = &hw->conf;
4284671c209SPrameela Rani Garnepudi 	struct ieee80211_vif *vif;
429d26a9559SPrameela Rani Garnepudi 	struct sk_buff *mac_bcn;
4304671c209SPrameela Rani Garnepudi 	u8 vap_id = 0, i;
4314671c209SPrameela Rani Garnepudi 	u16 tim_offset = 0;
432d26a9559SPrameela Rani Garnepudi 
4334671c209SPrameela Rani Garnepudi 	for (i = 0; i < RSI_MAX_VIFS; i++) {
4344671c209SPrameela Rani Garnepudi 		vif = adapter->vifs[i];
4354671c209SPrameela Rani Garnepudi 		if (!vif)
4364671c209SPrameela Rani Garnepudi 			continue;
4374671c209SPrameela Rani Garnepudi 		if ((vif->type == NL80211_IFTYPE_AP) ||
4384671c209SPrameela Rani Garnepudi 		    (vif->type == NL80211_IFTYPE_P2P_GO))
4394671c209SPrameela Rani Garnepudi 			break;
4404671c209SPrameela Rani Garnepudi 	}
4414671c209SPrameela Rani Garnepudi 	if (!vif)
4424671c209SPrameela Rani Garnepudi 		return -EINVAL;
443d26a9559SPrameela Rani Garnepudi 	mac_bcn = ieee80211_beacon_get_tim(adapter->hw,
4444671c209SPrameela Rani Garnepudi 					   vif,
445d26a9559SPrameela Rani Garnepudi 					   &tim_offset, NULL);
446d26a9559SPrameela Rani Garnepudi 	if (!mac_bcn) {
447d26a9559SPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n");
448d26a9559SPrameela Rani Garnepudi 		return -EINVAL;
449d26a9559SPrameela Rani Garnepudi 	}
450d26a9559SPrameela Rani Garnepudi 
451d26a9559SPrameela Rani Garnepudi 	common->beacon_cnt++;
452d26a9559SPrameela Rani Garnepudi 	bcn_frm = (struct rsi_data_desc *)skb->data;
453d26a9559SPrameela Rani Garnepudi 	rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q);
454d26a9559SPrameela Rani Garnepudi 	bcn_frm->header_len = MIN_802_11_HDR_LEN;
455d26a9559SPrameela Rani Garnepudi 	bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO |
456d26a9559SPrameela Rani Garnepudi 					  RSI_DATA_DESC_NO_ACK_IND |
457d26a9559SPrameela Rani Garnepudi 					  RSI_DATA_DESC_BEACON_FRAME |
458d26a9559SPrameela Rani Garnepudi 					  RSI_DATA_DESC_INSERT_TSF |
459d26a9559SPrameela Rani Garnepudi 					  RSI_DATA_DESC_INSERT_SEQ_NO |
460d26a9559SPrameela Rani Garnepudi 					  RATE_INFO_ENABLE);
461d26a9559SPrameela Rani Garnepudi 	bcn_frm->rate_info = cpu_to_le16(vap_id << 14);
462d26a9559SPrameela Rani Garnepudi 	bcn_frm->qid_tid = BEACON_HW_Q;
463d26a9559SPrameela Rani Garnepudi 
464d26a9559SPrameela Rani Garnepudi 	if (conf_is_ht40_plus(conf)) {
465d26a9559SPrameela Rani Garnepudi 		bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE);
466d26a9559SPrameela Rani Garnepudi 		bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12);
467d26a9559SPrameela Rani Garnepudi 	} else if (conf_is_ht40_minus(conf)) {
468d26a9559SPrameela Rani Garnepudi 		bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE);
469d26a9559SPrameela Rani Garnepudi 		bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12);
470d26a9559SPrameela Rani Garnepudi 	}
471d26a9559SPrameela Rani Garnepudi 
472d26a9559SPrameela Rani Garnepudi 	if (common->band == NL80211_BAND_2GHZ)
473b1c3a248SMarek Vasut 		bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1);
474d26a9559SPrameela Rani Garnepudi 	else
475b1c3a248SMarek Vasut 		bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6);
476d26a9559SPrameela Rani Garnepudi 
477d26a9559SPrameela Rani Garnepudi 	if (mac_bcn->data[tim_offset + 2] == 0)
478d26a9559SPrameela Rani Garnepudi 		bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
479d26a9559SPrameela Rani Garnepudi 
480d26a9559SPrameela Rani Garnepudi 	memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len);
481d26a9559SPrameela Rani Garnepudi 	skb_put(skb, mac_bcn->len + FRAME_DESC_SZ);
482d26a9559SPrameela Rani Garnepudi 
483d26a9559SPrameela Rani Garnepudi 	dev_kfree_skb(mac_bcn);
484d26a9559SPrameela Rani Garnepudi 
485d26a9559SPrameela Rani Garnepudi 	return 0;
486d26a9559SPrameela Rani Garnepudi }
487d26a9559SPrameela Rani Garnepudi 
488dfefb9f8SKees Cook static void bl_cmd_timeout(struct timer_list *t)
489b78e91bcSPrameela Rani Garnepudi {
490dfefb9f8SKees Cook 	struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer);
491b78e91bcSPrameela Rani Garnepudi 
492b78e91bcSPrameela Rani Garnepudi 	adapter->blcmd_timer_expired = true;
493b78e91bcSPrameela Rani Garnepudi 	del_timer(&adapter->bl_cmd_timer);
494b78e91bcSPrameela Rani Garnepudi }
495b78e91bcSPrameela Rani Garnepudi 
496b78e91bcSPrameela Rani Garnepudi static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout)
497b78e91bcSPrameela Rani Garnepudi {
498dfefb9f8SKees Cook 	timer_setup(&adapter->bl_cmd_timer, bl_cmd_timeout, 0);
499b78e91bcSPrameela Rani Garnepudi 	adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies);
500b78e91bcSPrameela Rani Garnepudi 
501b78e91bcSPrameela Rani Garnepudi 	adapter->blcmd_timer_expired = false;
502b78e91bcSPrameela Rani Garnepudi 	add_timer(&adapter->bl_cmd_timer);
503b78e91bcSPrameela Rani Garnepudi 
504b78e91bcSPrameela Rani Garnepudi 	return 0;
505b78e91bcSPrameela Rani Garnepudi }
506b78e91bcSPrameela Rani Garnepudi 
507b78e91bcSPrameela Rani Garnepudi static int bl_stop_cmd_timer(struct rsi_hw *adapter)
508b78e91bcSPrameela Rani Garnepudi {
509b78e91bcSPrameela Rani Garnepudi 	adapter->blcmd_timer_expired = false;
510b78e91bcSPrameela Rani Garnepudi 	if (timer_pending(&adapter->bl_cmd_timer))
511b78e91bcSPrameela Rani Garnepudi 		del_timer(&adapter->bl_cmd_timer);
512b78e91bcSPrameela Rani Garnepudi 
513b78e91bcSPrameela Rani Garnepudi 	return 0;
514b78e91bcSPrameela Rani Garnepudi }
515b78e91bcSPrameela Rani Garnepudi 
516b78e91bcSPrameela Rani Garnepudi static int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp,
517b78e91bcSPrameela Rani Garnepudi 			u16 *cmd_resp)
518b78e91bcSPrameela Rani Garnepudi {
519b78e91bcSPrameela Rani Garnepudi 	struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
520b78e91bcSPrameela Rani Garnepudi 	u32 regin_val = 0, regout_val = 0;
521b78e91bcSPrameela Rani Garnepudi 	u32 regin_input = 0;
522b78e91bcSPrameela Rani Garnepudi 	u8 output = 0;
523b78e91bcSPrameela Rani Garnepudi 	int status;
524b78e91bcSPrameela Rani Garnepudi 
525b78e91bcSPrameela Rani Garnepudi 	regin_input = (REGIN_INPUT | adapter->priv->coex_mode);
526b78e91bcSPrameela Rani Garnepudi 
527b78e91bcSPrameela Rani Garnepudi 	while (!adapter->blcmd_timer_expired) {
528b78e91bcSPrameela Rani Garnepudi 		regin_val = 0;
529b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->master_reg_read(adapter, SWBL_REGIN,
530b78e91bcSPrameela Rani Garnepudi 						  &regin_val, 2);
531b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
532b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
533b78e91bcSPrameela Rani Garnepudi 				"%s: Command %0x REGIN reading failed..\n",
534b78e91bcSPrameela Rani Garnepudi 				__func__, cmd);
535b78e91bcSPrameela Rani Garnepudi 			return status;
536b78e91bcSPrameela Rani Garnepudi 		}
537b78e91bcSPrameela Rani Garnepudi 		mdelay(1);
538b78e91bcSPrameela Rani Garnepudi 		if ((regin_val >> 12) != REGIN_VALID)
539b78e91bcSPrameela Rani Garnepudi 			break;
540b78e91bcSPrameela Rani Garnepudi 	}
541b78e91bcSPrameela Rani Garnepudi 	if (adapter->blcmd_timer_expired) {
542b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
543b78e91bcSPrameela Rani Garnepudi 			"%s: Command %0x REGIN reading timed out..\n",
544b78e91bcSPrameela Rani Garnepudi 			__func__, cmd);
545b78e91bcSPrameela Rani Garnepudi 		return -ETIMEDOUT;
546b78e91bcSPrameela Rani Garnepudi 	}
547b78e91bcSPrameela Rani Garnepudi 
548b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE,
549b78e91bcSPrameela Rani Garnepudi 		"Issuing write to Regin val:%0x sending cmd:%0x\n",
550b78e91bcSPrameela Rani Garnepudi 		regin_val, (cmd | regin_input << 8));
551b78e91bcSPrameela Rani Garnepudi 	status = hif_ops->master_reg_write(adapter, SWBL_REGIN,
552b78e91bcSPrameela Rani Garnepudi 					   (cmd | regin_input << 8), 2);
553b78e91bcSPrameela Rani Garnepudi 	if (status < 0)
554b78e91bcSPrameela Rani Garnepudi 		return status;
555b78e91bcSPrameela Rani Garnepudi 	mdelay(1);
556b78e91bcSPrameela Rani Garnepudi 
557b78e91bcSPrameela Rani Garnepudi 	if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) {
558b78e91bcSPrameela Rani Garnepudi 		/* JUMP_TO_ZERO_PC doesn't expect
559b78e91bcSPrameela Rani Garnepudi 		 * any response. So return from here
560b78e91bcSPrameela Rani Garnepudi 		 */
561b78e91bcSPrameela Rani Garnepudi 		return 0;
562b78e91bcSPrameela Rani Garnepudi 	}
563b78e91bcSPrameela Rani Garnepudi 
564b78e91bcSPrameela Rani Garnepudi 	while (!adapter->blcmd_timer_expired) {
565b78e91bcSPrameela Rani Garnepudi 		regout_val = 0;
566b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->master_reg_read(adapter, SWBL_REGOUT,
567b78e91bcSPrameela Rani Garnepudi 					     &regout_val, 2);
568b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
569b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
570b78e91bcSPrameela Rani Garnepudi 				"%s: Command %0x REGOUT reading failed..\n",
571b78e91bcSPrameela Rani Garnepudi 				__func__, cmd);
572b78e91bcSPrameela Rani Garnepudi 			return status;
573b78e91bcSPrameela Rani Garnepudi 		}
574b78e91bcSPrameela Rani Garnepudi 		mdelay(1);
575b78e91bcSPrameela Rani Garnepudi 		if ((regout_val >> 8) == REGOUT_VALID)
576b78e91bcSPrameela Rani Garnepudi 			break;
577b78e91bcSPrameela Rani Garnepudi 	}
578b78e91bcSPrameela Rani Garnepudi 	if (adapter->blcmd_timer_expired) {
579b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
580b78e91bcSPrameela Rani Garnepudi 			"%s: Command %0x REGOUT reading timed out..\n",
581b78e91bcSPrameela Rani Garnepudi 			__func__, cmd);
582b78e91bcSPrameela Rani Garnepudi 		return status;
583b78e91bcSPrameela Rani Garnepudi 	}
584b78e91bcSPrameela Rani Garnepudi 
585b78e91bcSPrameela Rani Garnepudi 	*cmd_resp = ((u16 *)&regout_val)[0] & 0xffff;
586b78e91bcSPrameela Rani Garnepudi 
587b78e91bcSPrameela Rani Garnepudi 	output = ((u8 *)&regout_val)[0] & 0xff;
588b78e91bcSPrameela Rani Garnepudi 
589b78e91bcSPrameela Rani Garnepudi 	status = hif_ops->master_reg_write(adapter, SWBL_REGOUT,
590b78e91bcSPrameela Rani Garnepudi 					   (cmd | REGOUT_INVALID << 8), 2);
591b78e91bcSPrameela Rani Garnepudi 	if (status < 0) {
592b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
593b78e91bcSPrameela Rani Garnepudi 			"%s: Command %0x REGOUT writing failed..\n",
594b78e91bcSPrameela Rani Garnepudi 			__func__, cmd);
595b78e91bcSPrameela Rani Garnepudi 		return status;
596b78e91bcSPrameela Rani Garnepudi 	}
597b78e91bcSPrameela Rani Garnepudi 	mdelay(1);
598b78e91bcSPrameela Rani Garnepudi 
599b78e91bcSPrameela Rani Garnepudi 	if (output != exp_resp) {
600b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
601b78e91bcSPrameela Rani Garnepudi 			"%s: Recvd resp %x for cmd %0x\n",
602b78e91bcSPrameela Rani Garnepudi 			__func__, output, cmd);
603b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
604b78e91bcSPrameela Rani Garnepudi 	}
605b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE,
606b78e91bcSPrameela Rani Garnepudi 		"%s: Recvd Expected resp %x for cmd %0x\n",
607b78e91bcSPrameela Rani Garnepudi 		__func__, output, cmd);
608b78e91bcSPrameela Rani Garnepudi 
609b78e91bcSPrameela Rani Garnepudi 	return 0;
610b78e91bcSPrameela Rani Garnepudi }
611b78e91bcSPrameela Rani Garnepudi 
612b78e91bcSPrameela Rani Garnepudi static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str)
613b78e91bcSPrameela Rani Garnepudi {
614b78e91bcSPrameela Rani Garnepudi 	u16 regout_val = 0;
615b78e91bcSPrameela Rani Garnepudi 	u32 timeout;
616b78e91bcSPrameela Rani Garnepudi 	int status;
617b78e91bcSPrameela Rani Garnepudi 
618b78e91bcSPrameela Rani Garnepudi 	if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID))
619b78e91bcSPrameela Rani Garnepudi 		timeout = BL_BURN_TIMEOUT;
620b78e91bcSPrameela Rani Garnepudi 	else
621b78e91bcSPrameela Rani Garnepudi 		timeout = BL_CMD_TIMEOUT;
622b78e91bcSPrameela Rani Garnepudi 
623b78e91bcSPrameela Rani Garnepudi 	bl_start_cmd_timer(adapter, timeout);
624b78e91bcSPrameela Rani Garnepudi 	status = bl_write_cmd(adapter, cmd, exp_resp, &regout_val);
625b78e91bcSPrameela Rani Garnepudi 	if (status < 0) {
62692aafe77SJohan Hovold 		bl_stop_cmd_timer(adapter);
627b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
628b78e91bcSPrameela Rani Garnepudi 			"%s: Command %s (%0x) writing failed..\n",
629b78e91bcSPrameela Rani Garnepudi 			__func__, str, cmd);
630b78e91bcSPrameela Rani Garnepudi 		return status;
631b78e91bcSPrameela Rani Garnepudi 	}
632b78e91bcSPrameela Rani Garnepudi 	bl_stop_cmd_timer(adapter);
633b78e91bcSPrameela Rani Garnepudi 	return 0;
634b78e91bcSPrameela Rani Garnepudi }
635b78e91bcSPrameela Rani Garnepudi 
636b78e91bcSPrameela Rani Garnepudi #define CHECK_SUM_OFFSET 20
637b78e91bcSPrameela Rani Garnepudi #define LEN_OFFSET 8
638b78e91bcSPrameela Rani Garnepudi #define ADDR_OFFSET 16
639b78e91bcSPrameela Rani Garnepudi static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
640b78e91bcSPrameela Rani Garnepudi 			   u32 content_size)
641b78e91bcSPrameela Rani Garnepudi {
642b78e91bcSPrameela Rani Garnepudi 	struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
643f7005466SSiva Rebbagondla 	struct bl_header *bl_hdr;
644b78e91bcSPrameela Rani Garnepudi 	u32 write_addr, write_len;
645b78e91bcSPrameela Rani Garnepudi 	int status;
646b78e91bcSPrameela Rani Garnepudi 
647f7005466SSiva Rebbagondla 	bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL);
648f7005466SSiva Rebbagondla 	if (!bl_hdr)
649f7005466SSiva Rebbagondla 		return -ENOMEM;
650f7005466SSiva Rebbagondla 
651f7005466SSiva Rebbagondla 	bl_hdr->flags = 0;
652f7005466SSiva Rebbagondla 	bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode);
653f7005466SSiva Rebbagondla 	bl_hdr->check_sum =
654f7005466SSiva Rebbagondla 		cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]);
655f7005466SSiva Rebbagondla 	bl_hdr->flash_start_address =
656f7005466SSiva Rebbagondla 		cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]);
657f7005466SSiva Rebbagondla 	bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]);
658b78e91bcSPrameela Rani Garnepudi 	write_len = sizeof(struct bl_header);
659b78e91bcSPrameela Rani Garnepudi 
660b78e91bcSPrameela Rani Garnepudi 	if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
661b78e91bcSPrameela Rani Garnepudi 		write_addr = PING_BUFFER_ADDRESS;
662b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->write_reg_multiple(adapter, write_addr,
663f7005466SSiva Rebbagondla 						 (u8 *)bl_hdr, write_len);
664b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
665b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
666b78e91bcSPrameela Rani Garnepudi 				"%s: Failed to load Version/CRC structure\n",
667b78e91bcSPrameela Rani Garnepudi 				__func__);
668f7005466SSiva Rebbagondla 			goto fail;
669b78e91bcSPrameela Rani Garnepudi 		}
670b78e91bcSPrameela Rani Garnepudi 	} else {
671b78e91bcSPrameela Rani Garnepudi 		write_addr = PING_BUFFER_ADDRESS >> 16;
672b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->master_access_msword(adapter, write_addr);
673b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
674b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
675b78e91bcSPrameela Rani Garnepudi 				"%s: Unable to set ms word to common reg\n",
676b78e91bcSPrameela Rani Garnepudi 				__func__);
677f7005466SSiva Rebbagondla 			goto fail;
678b78e91bcSPrameela Rani Garnepudi 		}
679b78e91bcSPrameela Rani Garnepudi 		write_addr = RSI_SD_REQUEST_MASTER |
680b78e91bcSPrameela Rani Garnepudi 			     (PING_BUFFER_ADDRESS & 0xFFFF);
681b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->write_reg_multiple(adapter, write_addr,
682f7005466SSiva Rebbagondla 						 (u8 *)bl_hdr, write_len);
683b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
684b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
685b78e91bcSPrameela Rani Garnepudi 				"%s: Failed to load Version/CRC structure\n",
686b78e91bcSPrameela Rani Garnepudi 				__func__);
687f7005466SSiva Rebbagondla 			goto fail;
688f7005466SSiva Rebbagondla 		}
689f7005466SSiva Rebbagondla 	}
690f7005466SSiva Rebbagondla 	status = 0;
691f7005466SSiva Rebbagondla fail:
692f7005466SSiva Rebbagondla 	kfree(bl_hdr);
693b78e91bcSPrameela Rani Garnepudi 	return status;
694b78e91bcSPrameela Rani Garnepudi }
695b78e91bcSPrameela Rani Garnepudi 
696b78e91bcSPrameela Rani Garnepudi static u32 read_flash_capacity(struct rsi_hw *adapter)
697b78e91bcSPrameela Rani Garnepudi {
698b78e91bcSPrameela Rani Garnepudi 	u32 flash_sz = 0;
699b78e91bcSPrameela Rani Garnepudi 
700b78e91bcSPrameela Rani Garnepudi 	if ((adapter->host_intf_ops->master_reg_read(adapter, FLASH_SIZE_ADDR,
701b78e91bcSPrameela Rani Garnepudi 						     &flash_sz, 2)) < 0) {
702b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
703b78e91bcSPrameela Rani Garnepudi 			"%s: Flash size reading failed..\n",
704b78e91bcSPrameela Rani Garnepudi 			__func__);
705b78e91bcSPrameela Rani Garnepudi 		return 0;
706b78e91bcSPrameela Rani Garnepudi 	}
707b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz);
708b78e91bcSPrameela Rani Garnepudi 
709b78e91bcSPrameela Rani Garnepudi 	return (flash_sz * 1024); /* Return size in kbytes */
710b78e91bcSPrameela Rani Garnepudi }
711b78e91bcSPrameela Rani Garnepudi 
712b78e91bcSPrameela Rani Garnepudi static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size)
713b78e91bcSPrameela Rani Garnepudi {
714b78e91bcSPrameela Rani Garnepudi 	struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
715b78e91bcSPrameela Rani Garnepudi 	u32 block_size = adapter->block_size;
716b78e91bcSPrameela Rani Garnepudi 	u32 cmd_addr;
717b78e91bcSPrameela Rani Garnepudi 	u16 cmd_resp, cmd_req;
718b78e91bcSPrameela Rani Garnepudi 	u8 *str;
719b78e91bcSPrameela Rani Garnepudi 	int status;
720b78e91bcSPrameela Rani Garnepudi 
721b78e91bcSPrameela Rani Garnepudi 	if (cmd == PING_WRITE) {
722b78e91bcSPrameela Rani Garnepudi 		cmd_addr = PING_BUFFER_ADDRESS;
723b78e91bcSPrameela Rani Garnepudi 		cmd_resp = PONG_AVAIL;
724b78e91bcSPrameela Rani Garnepudi 		cmd_req = PING_VALID;
725b78e91bcSPrameela Rani Garnepudi 		str = "PING_VALID";
726b78e91bcSPrameela Rani Garnepudi 	} else {
727b78e91bcSPrameela Rani Garnepudi 		cmd_addr = PONG_BUFFER_ADDRESS;
728b78e91bcSPrameela Rani Garnepudi 		cmd_resp = PING_AVAIL;
729b78e91bcSPrameela Rani Garnepudi 		cmd_req = PONG_VALID;
730b78e91bcSPrameela Rani Garnepudi 		str = "PONG_VALID";
731b78e91bcSPrameela Rani Garnepudi 	}
732b78e91bcSPrameela Rani Garnepudi 
733b78e91bcSPrameela Rani Garnepudi 	status = hif_ops->load_data_master_write(adapter, cmd_addr, size,
734b78e91bcSPrameela Rani Garnepudi 					    block_size, addr);
735b78e91bcSPrameela Rani Garnepudi 	if (status) {
736b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n",
737b78e91bcSPrameela Rani Garnepudi 			__func__, *addr);
738b78e91bcSPrameela Rani Garnepudi 		return status;
739b78e91bcSPrameela Rani Garnepudi 	}
740b78e91bcSPrameela Rani Garnepudi 
741b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, cmd_req, cmd_resp, str);
74292aafe77SJohan Hovold 	if (status)
743b78e91bcSPrameela Rani Garnepudi 		return status;
74492aafe77SJohan Hovold 
745b78e91bcSPrameela Rani Garnepudi 	return 0;
746b78e91bcSPrameela Rani Garnepudi }
747b78e91bcSPrameela Rani Garnepudi 
748b78e91bcSPrameela Rani Garnepudi static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content,
749b78e91bcSPrameela Rani Garnepudi 			   u32 content_size)
750b78e91bcSPrameela Rani Garnepudi {
75135204d0aSColin Ian King 	u8 cmd;
752b78e91bcSPrameela Rani Garnepudi 	u32 temp_content_size, num_flash, index;
753b78e91bcSPrameela Rani Garnepudi 	u32 flash_start_address;
754b78e91bcSPrameela Rani Garnepudi 	int status;
755b78e91bcSPrameela Rani Garnepudi 
756b78e91bcSPrameela Rani Garnepudi 	if (content_size > MAX_FLASH_FILE_SIZE) {
757b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
758b78e91bcSPrameela Rani Garnepudi 			"%s: Flash Content size is more than 400K %u\n",
759b78e91bcSPrameela Rani Garnepudi 			__func__, MAX_FLASH_FILE_SIZE);
760b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
761b78e91bcSPrameela Rani Garnepudi 	}
762b78e91bcSPrameela Rani Garnepudi 
763b78e91bcSPrameela Rani Garnepudi 	flash_start_address = *(u32 *)&flash_content[FLASH_START_ADDRESS];
764b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address);
765b78e91bcSPrameela Rani Garnepudi 
766b78e91bcSPrameela Rani Garnepudi 	if (flash_start_address < FW_IMAGE_MIN_ADDRESS) {
767b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
768b78e91bcSPrameela Rani Garnepudi 			"%s: Fw image Flash Start Address is less than 64K\n",
769b78e91bcSPrameela Rani Garnepudi 			__func__);
770b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
771b78e91bcSPrameela Rani Garnepudi 	}
772b78e91bcSPrameela Rani Garnepudi 
773b78e91bcSPrameela Rani Garnepudi 	if (flash_start_address % FLASH_SECTOR_SIZE) {
774b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
775b78e91bcSPrameela Rani Garnepudi 			"%s: Flash Start Address is not multiple of 4K\n",
776b78e91bcSPrameela Rani Garnepudi 			__func__);
777b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
778b78e91bcSPrameela Rani Garnepudi 	}
779b78e91bcSPrameela Rani Garnepudi 
780b78e91bcSPrameela Rani Garnepudi 	if ((flash_start_address + content_size) > adapter->flash_capacity) {
781b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
782b78e91bcSPrameela Rani Garnepudi 			"%s: Flash Content will cross max flash size\n",
783b78e91bcSPrameela Rani Garnepudi 			__func__);
784b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
785b78e91bcSPrameela Rani Garnepudi 	}
786b78e91bcSPrameela Rani Garnepudi 
787b78e91bcSPrameela Rani Garnepudi 	temp_content_size  = content_size;
788b78e91bcSPrameela Rani Garnepudi 	num_flash = content_size / FLASH_WRITE_CHUNK_SIZE;
789b78e91bcSPrameela Rani Garnepudi 
790b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "content_size: %d, num_flash: %d\n",
791b78e91bcSPrameela Rani Garnepudi 		content_size, num_flash);
792b78e91bcSPrameela Rani Garnepudi 
793b78e91bcSPrameela Rani Garnepudi 	for (index = 0; index <= num_flash; index++) {
794b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(INFO_ZONE, "flash index: %d\n", index);
795b78e91bcSPrameela Rani Garnepudi 		if (index != num_flash) {
796b78e91bcSPrameela Rani Garnepudi 			content_size = FLASH_WRITE_CHUNK_SIZE;
797b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(INFO_ZONE, "QSPI content_size:%d\n",
798b78e91bcSPrameela Rani Garnepudi 				content_size);
799b78e91bcSPrameela Rani Garnepudi 		} else {
800b78e91bcSPrameela Rani Garnepudi 			content_size =
801b78e91bcSPrameela Rani Garnepudi 				temp_content_size % FLASH_WRITE_CHUNK_SIZE;
802b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(INFO_ZONE,
803b78e91bcSPrameela Rani Garnepudi 				"Writing last sector content_size:%d\n",
804b78e91bcSPrameela Rani Garnepudi 				content_size);
805b78e91bcSPrameela Rani Garnepudi 			if (!content_size) {
806b78e91bcSPrameela Rani Garnepudi 				rsi_dbg(INFO_ZONE, "instruction size zero\n");
807b78e91bcSPrameela Rani Garnepudi 				break;
808b78e91bcSPrameela Rani Garnepudi 			}
809b78e91bcSPrameela Rani Garnepudi 		}
810b78e91bcSPrameela Rani Garnepudi 
811b78e91bcSPrameela Rani Garnepudi 		if (index % 2)
812b78e91bcSPrameela Rani Garnepudi 			cmd = PING_WRITE;
813b78e91bcSPrameela Rani Garnepudi 		else
814b78e91bcSPrameela Rani Garnepudi 			cmd = PONG_WRITE;
815b78e91bcSPrameela Rani Garnepudi 
816b78e91bcSPrameela Rani Garnepudi 		status = ping_pong_write(adapter, cmd, flash_content,
817b78e91bcSPrameela Rani Garnepudi 					 content_size);
818b78e91bcSPrameela Rani Garnepudi 		if (status) {
819b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE, "%s: Unable to load %d block\n",
820b78e91bcSPrameela Rani Garnepudi 				__func__, index);
821b78e91bcSPrameela Rani Garnepudi 			return status;
822b78e91bcSPrameela Rani Garnepudi 		}
823b78e91bcSPrameela Rani Garnepudi 
824b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(INFO_ZONE,
825b78e91bcSPrameela Rani Garnepudi 			"%s: Successfully loaded %d instructions\n",
826b78e91bcSPrameela Rani Garnepudi 			__func__, index);
827b78e91bcSPrameela Rani Garnepudi 		flash_content += content_size;
828b78e91bcSPrameela Rani Garnepudi 	}
829b78e91bcSPrameela Rani Garnepudi 
830b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL,
831b78e91bcSPrameela Rani Garnepudi 			"EOF_REACHED");
83292aafe77SJohan Hovold 	if (status)
833b78e91bcSPrameela Rani Garnepudi 		return status;
83492aafe77SJohan Hovold 
835b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n");
836b78e91bcSPrameela Rani Garnepudi 	return 0;
837b78e91bcSPrameela Rani Garnepudi }
838b78e91bcSPrameela Rani Garnepudi 
8393ac61578SSiva Rebbagondla static int rsi_hal_prepare_fwload(struct rsi_hw *adapter)
840b78e91bcSPrameela Rani Garnepudi {
841b78e91bcSPrameela Rani Garnepudi 	struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
8423ac61578SSiva Rebbagondla 	u32 regout_val = 0;
843b78e91bcSPrameela Rani Garnepudi 	int status;
844b78e91bcSPrameela Rani Garnepudi 
845b78e91bcSPrameela Rani Garnepudi 	bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
846b78e91bcSPrameela Rani Garnepudi 
847b78e91bcSPrameela Rani Garnepudi 	while (!adapter->blcmd_timer_expired) {
848b78e91bcSPrameela Rani Garnepudi 		status = hif_ops->master_reg_read(adapter, SWBL_REGOUT,
8493ac61578SSiva Rebbagondla 						  &regout_val,
8503ac61578SSiva Rebbagondla 						  RSI_COMMON_REG_SIZE);
851b78e91bcSPrameela Rani Garnepudi 		if (status < 0) {
85292aafe77SJohan Hovold 			bl_stop_cmd_timer(adapter);
853b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
854b78e91bcSPrameela Rani Garnepudi 				"%s: REGOUT read failed\n", __func__);
855b78e91bcSPrameela Rani Garnepudi 			return status;
856b78e91bcSPrameela Rani Garnepudi 		}
857b78e91bcSPrameela Rani Garnepudi 		mdelay(1);
858b78e91bcSPrameela Rani Garnepudi 		if ((regout_val >> 8) == REGOUT_VALID)
859b78e91bcSPrameela Rani Garnepudi 			break;
860b78e91bcSPrameela Rani Garnepudi 	}
861b78e91bcSPrameela Rani Garnepudi 	if (adapter->blcmd_timer_expired) {
862b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__);
863b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
864b78e91bcSPrameela Rani Garnepudi 			"%s: Soft boot loader not present\n", __func__);
865b78e91bcSPrameela Rani Garnepudi 		return -ETIMEDOUT;
866b78e91bcSPrameela Rani Garnepudi 	}
867b78e91bcSPrameela Rani Garnepudi 	bl_stop_cmd_timer(adapter);
868b78e91bcSPrameela Rani Garnepudi 
869b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n",
870b78e91bcSPrameela Rani Garnepudi 		(regout_val & 0xff));
871b78e91bcSPrameela Rani Garnepudi 
872b78e91bcSPrameela Rani Garnepudi 	status = hif_ops->master_reg_write(adapter, SWBL_REGOUT,
8733ac61578SSiva Rebbagondla 					   (REGOUT_INVALID |
8743ac61578SSiva Rebbagondla 					    REGOUT_INVALID << 8),
8753ac61578SSiva Rebbagondla 					   RSI_COMMON_REG_SIZE);
8763ac61578SSiva Rebbagondla 	if (status < 0)
877b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__);
8783ac61578SSiva Rebbagondla 	else
8793ac61578SSiva Rebbagondla 		rsi_dbg(INFO_ZONE,
8803ac61578SSiva Rebbagondla 			"===> Device is ready to load firmware <===\n");
8813ac61578SSiva Rebbagondla 
882b78e91bcSPrameela Rani Garnepudi 	return status;
883b78e91bcSPrameela Rani Garnepudi }
8843ac61578SSiva Rebbagondla 
8853ac61578SSiva Rebbagondla static int rsi_load_9113_firmware(struct rsi_hw *adapter)
8863ac61578SSiva Rebbagondla {
8873ac61578SSiva Rebbagondla 	struct rsi_common *common = adapter->priv;
8883ac61578SSiva Rebbagondla 	const struct firmware *fw_entry = NULL;
8893ac61578SSiva Rebbagondla 	u32 content_size;
8903ac61578SSiva Rebbagondla 	u16 tmp_regout_val = 0;
8913ac61578SSiva Rebbagondla 	struct ta_metadata *metadata_p;
8923ac61578SSiva Rebbagondla 	int status;
893b78e91bcSPrameela Rani Garnepudi 
894b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
895b78e91bcSPrameela Rani Garnepudi 			"AUTO_READ_CMD");
896b78e91bcSPrameela Rani Garnepudi 	if (status < 0)
897b78e91bcSPrameela Rani Garnepudi 		return status;
898b78e91bcSPrameela Rani Garnepudi 
899b78e91bcSPrameela Rani Garnepudi 	adapter->flash_capacity = read_flash_capacity(adapter);
900b78e91bcSPrameela Rani Garnepudi 	if (adapter->flash_capacity <= 0) {
901b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
902b78e91bcSPrameela Rani Garnepudi 			"%s: Unable to read flash size from EEPROM\n",
903b78e91bcSPrameela Rani Garnepudi 			__func__);
904b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
905b78e91bcSPrameela Rani Garnepudi 	}
906b78e91bcSPrameela Rani Garnepudi 
907b78e91bcSPrameela Rani Garnepudi 	metadata_p = &metadata_flash_content[adapter->priv->coex_mode];
908b78e91bcSPrameela Rani Garnepudi 
909b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INIT_ZONE, "%s: Loading file %s\n", __func__, metadata_p->name);
910b78e91bcSPrameela Rani Garnepudi 	adapter->fw_file_name = metadata_p->name;
911b78e91bcSPrameela Rani Garnepudi 
912b78e91bcSPrameela Rani Garnepudi 	status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
913b78e91bcSPrameela Rani Garnepudi 	if (status < 0) {
914b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
915b78e91bcSPrameela Rani Garnepudi 			__func__, metadata_p->name);
916b78e91bcSPrameela Rani Garnepudi 		return status;
917b78e91bcSPrameela Rani Garnepudi 	}
918b78e91bcSPrameela Rani Garnepudi 	content_size = fw_entry->size;
919b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size);
920b78e91bcSPrameela Rani Garnepudi 
921192524a4SPavani Muthyala 	/* Get the firmware version */
922192524a4SPavani Muthyala 	common->lmac_ver.ver.info.fw_ver[0] =
9233ac61578SSiva Rebbagondla 		fw_entry->data[LMAC_VER_OFFSET_9113] & 0xFF;
924192524a4SPavani Muthyala 	common->lmac_ver.ver.info.fw_ver[1] =
9253ac61578SSiva Rebbagondla 		fw_entry->data[LMAC_VER_OFFSET_9113 + 1] & 0xFF;
9263ac61578SSiva Rebbagondla 	common->lmac_ver.major =
9273ac61578SSiva Rebbagondla 		fw_entry->data[LMAC_VER_OFFSET_9113 + 2] & 0xFF;
928192524a4SPavani Muthyala 	common->lmac_ver.release_num =
9293ac61578SSiva Rebbagondla 		fw_entry->data[LMAC_VER_OFFSET_9113 + 3] & 0xFF;
9303ac61578SSiva Rebbagondla 	common->lmac_ver.minor =
9313ac61578SSiva Rebbagondla 		fw_entry->data[LMAC_VER_OFFSET_9113 + 4] & 0xFF;
932192524a4SPavani Muthyala 	common->lmac_ver.patch_num = 0;
933192524a4SPavani Muthyala 	rsi_print_version(common);
934192524a4SPavani Muthyala 
935bae40292SSiva Rebbagondla 	status = bl_write_header(adapter, (u8 *)fw_entry->data, content_size);
936b78e91bcSPrameela Rani Garnepudi 	if (status) {
937b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
938b78e91bcSPrameela Rani Garnepudi 			"%s: RPS Image header loading failed\n",
939b78e91bcSPrameela Rani Garnepudi 			__func__);
940b78e91bcSPrameela Rani Garnepudi 		goto fail;
941b78e91bcSPrameela Rani Garnepudi 	}
942b78e91bcSPrameela Rani Garnepudi 
943b78e91bcSPrameela Rani Garnepudi 	bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
944b78e91bcSPrameela Rani Garnepudi 	status = bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val);
945b78e91bcSPrameela Rani Garnepudi 	if (status) {
946b78e91bcSPrameela Rani Garnepudi 		bl_stop_cmd_timer(adapter);
947b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE,
948b78e91bcSPrameela Rani Garnepudi 			"%s: CHECK_CRC Command writing failed..\n",
949b78e91bcSPrameela Rani Garnepudi 			__func__);
950b78e91bcSPrameela Rani Garnepudi 		if ((tmp_regout_val & 0xff) == CMD_FAIL) {
951b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
952b78e91bcSPrameela Rani Garnepudi 				"CRC Fail.. Proceeding to Upgrade mode\n");
953b78e91bcSPrameela Rani Garnepudi 			goto fw_upgrade;
954b78e91bcSPrameela Rani Garnepudi 		}
955b78e91bcSPrameela Rani Garnepudi 	}
956b78e91bcSPrameela Rani Garnepudi 	bl_stop_cmd_timer(adapter);
957b78e91bcSPrameela Rani Garnepudi 
958b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE");
959b78e91bcSPrameela Rani Garnepudi 	if (status)
960b78e91bcSPrameela Rani Garnepudi 		goto fail;
961b78e91bcSPrameela Rani Garnepudi 
962b78e91bcSPrameela Rani Garnepudi load_image_cmd:
963b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, LOAD_HOSTED_FW, LOADING_INITIATED,
964b78e91bcSPrameela Rani Garnepudi 			"LOAD_HOSTED_FW");
965b78e91bcSPrameela Rani Garnepudi 	if (status)
966b78e91bcSPrameela Rani Garnepudi 		goto fail;
967b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "Load Image command passed..\n");
968b78e91bcSPrameela Rani Garnepudi 	goto success;
969b78e91bcSPrameela Rani Garnepudi 
970b78e91bcSPrameela Rani Garnepudi fw_upgrade:
971b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE");
972b78e91bcSPrameela Rani Garnepudi 	if (status)
973b78e91bcSPrameela Rani Garnepudi 		goto fail;
974b78e91bcSPrameela Rani Garnepudi 
975b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n");
976b78e91bcSPrameela Rani Garnepudi 
977bae40292SSiva Rebbagondla 	status = auto_fw_upgrade(adapter, (u8 *)fw_entry->data, content_size);
978b78e91bcSPrameela Rani Garnepudi 	if (status == 0) {
979b78e91bcSPrameela Rani Garnepudi 		rsi_dbg(ERR_ZONE, "Firmware upgradation Done\n");
980b78e91bcSPrameela Rani Garnepudi 		goto load_image_cmd;
981b78e91bcSPrameela Rani Garnepudi 	}
982b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n");
983b78e91bcSPrameela Rani Garnepudi 
984b78e91bcSPrameela Rani Garnepudi 	status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
985b78e91bcSPrameela Rani Garnepudi 			"AUTO_READ_MODE");
986b78e91bcSPrameela Rani Garnepudi 	if (status)
987b78e91bcSPrameela Rani Garnepudi 		goto fail;
988b78e91bcSPrameela Rani Garnepudi 
989b78e91bcSPrameela Rani Garnepudi success:
990b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(ERR_ZONE, "***** Firmware Loading successful *****\n");
991b78e91bcSPrameela Rani Garnepudi 	release_firmware(fw_entry);
992b78e91bcSPrameela Rani Garnepudi 	return 0;
993b78e91bcSPrameela Rani Garnepudi 
994b78e91bcSPrameela Rani Garnepudi fail:
995b78e91bcSPrameela Rani Garnepudi 	rsi_dbg(ERR_ZONE, "##### Firmware loading failed #####\n");
996b78e91bcSPrameela Rani Garnepudi 	release_firmware(fw_entry);
997b78e91bcSPrameela Rani Garnepudi 	return status;
998b78e91bcSPrameela Rani Garnepudi }
999b78e91bcSPrameela Rani Garnepudi 
1000e5a1ecc9SSiva Rebbagondla static int rsi_load_9116_firmware(struct rsi_hw *adapter)
1001e5a1ecc9SSiva Rebbagondla {
1002e5a1ecc9SSiva Rebbagondla 	struct rsi_common *common = adapter->priv;
1003e5a1ecc9SSiva Rebbagondla 	struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
1004e5a1ecc9SSiva Rebbagondla 	const struct firmware *fw_entry;
1005e5a1ecc9SSiva Rebbagondla 	struct ta_metadata *metadata_p;
1006e5a1ecc9SSiva Rebbagondla 	u8 *ta_firmware, *fw_p;
1007e5a1ecc9SSiva Rebbagondla 	struct bootload_ds bootload_ds;
1008e5a1ecc9SSiva Rebbagondla 	u32 instructions_sz, base_address;
1009e5a1ecc9SSiva Rebbagondla 	u16 block_size = adapter->block_size;
1010e5a1ecc9SSiva Rebbagondla 	u32 dest, len;
1011e5a1ecc9SSiva Rebbagondla 	int status, cnt;
1012e5a1ecc9SSiva Rebbagondla 
1013e5a1ecc9SSiva Rebbagondla 	rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n");
1014e5a1ecc9SSiva Rebbagondla 
1015e5a1ecc9SSiva Rebbagondla 	if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
1016e5a1ecc9SSiva Rebbagondla 		status = bl_cmd(adapter, POLLING_MODE, CMD_PASS,
1017e5a1ecc9SSiva Rebbagondla 				"POLLING_MODE");
1018e5a1ecc9SSiva Rebbagondla 		if (status < 0)
1019e5a1ecc9SSiva Rebbagondla 			return status;
1020e5a1ecc9SSiva Rebbagondla 	}
1021e5a1ecc9SSiva Rebbagondla 
1022e5a1ecc9SSiva Rebbagondla 	status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST,
1023e5a1ecc9SSiva Rebbagondla 					   RAM_384K_ACCESS_FROM_TA,
1024e5a1ecc9SSiva Rebbagondla 					   RSI_9116_REG_SIZE);
1025e5a1ecc9SSiva Rebbagondla 	if (status < 0) {
1026e5a1ecc9SSiva Rebbagondla 		rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n",
1027e5a1ecc9SSiva Rebbagondla 			__func__);
1028e5a1ecc9SSiva Rebbagondla 		return status;
1029e5a1ecc9SSiva Rebbagondla 	}
1030e5a1ecc9SSiva Rebbagondla 
1031e5a1ecc9SSiva Rebbagondla 	metadata_p = &metadata[adapter->priv->coex_mode];
1032e5a1ecc9SSiva Rebbagondla 	rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name);
1033e5a1ecc9SSiva Rebbagondla 	status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
1034e5a1ecc9SSiva Rebbagondla 	if (status < 0) {
1035e5a1ecc9SSiva Rebbagondla 		rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
1036e5a1ecc9SSiva Rebbagondla 			__func__, metadata_p->name);
1037e5a1ecc9SSiva Rebbagondla 		return status;
1038e5a1ecc9SSiva Rebbagondla 	}
1039e5a1ecc9SSiva Rebbagondla 
1040e5a1ecc9SSiva Rebbagondla 	ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
1041e5a1ecc9SSiva Rebbagondla 	if (!ta_firmware)
1042e5a1ecc9SSiva Rebbagondla 		goto fail_release_fw;
1043e5a1ecc9SSiva Rebbagondla 	fw_p = ta_firmware;
1044e5a1ecc9SSiva Rebbagondla 	instructions_sz = fw_entry->size;
1045e5a1ecc9SSiva Rebbagondla 	rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz);
1046e5a1ecc9SSiva Rebbagondla 
1047e5a1ecc9SSiva Rebbagondla 	common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116];
1048e5a1ecc9SSiva Rebbagondla 	common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1];
1049e5a1ecc9SSiva Rebbagondla 	common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2];
1050e5a1ecc9SSiva Rebbagondla 	common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3];
1051e5a1ecc9SSiva Rebbagondla 	common->lmac_ver.ver.info.fw_ver[0] =
1052e5a1ecc9SSiva Rebbagondla 		ta_firmware[LMAC_VER_OFFSET_9116 + 4];
1053e5a1ecc9SSiva Rebbagondla 
1054e5a1ecc9SSiva Rebbagondla 	if (instructions_sz % FW_ALIGN_SIZE)
1055e5a1ecc9SSiva Rebbagondla 		instructions_sz +=
1056e5a1ecc9SSiva Rebbagondla 			(FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE));
1057e5a1ecc9SSiva Rebbagondla 	rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz);
1058e5a1ecc9SSiva Rebbagondla 
1059e5a1ecc9SSiva Rebbagondla 	if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) {
1060e5a1ecc9SSiva Rebbagondla 		memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds));
1061e5a1ecc9SSiva Rebbagondla 		fw_p += le16_to_cpu(bootload_ds.offset);
1062e5a1ecc9SSiva Rebbagondla 		rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p);
1063e5a1ecc9SSiva Rebbagondla 
1064e5a1ecc9SSiva Rebbagondla 		cnt = 0;
1065e5a1ecc9SSiva Rebbagondla 		do {
1066e5a1ecc9SSiva Rebbagondla 			rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n",
1067e5a1ecc9SSiva Rebbagondla 				__func__, cnt);
1068e5a1ecc9SSiva Rebbagondla 
1069e5a1ecc9SSiva Rebbagondla 			dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr);
1070e5a1ecc9SSiva Rebbagondla 			len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
1071e5a1ecc9SSiva Rebbagondla 			      RSI_BL_CTRL_LEN_MASK;
1072e5a1ecc9SSiva Rebbagondla 			rsi_dbg(INFO_ZONE, "length %d destination %x\n",
1073e5a1ecc9SSiva Rebbagondla 				len, dest);
1074e5a1ecc9SSiva Rebbagondla 
1075e5a1ecc9SSiva Rebbagondla 			status = hif_ops->load_data_master_write(adapter, dest,
1076e5a1ecc9SSiva Rebbagondla 								 len,
1077e5a1ecc9SSiva Rebbagondla 								 block_size,
1078e5a1ecc9SSiva Rebbagondla 								 fw_p);
1079e5a1ecc9SSiva Rebbagondla 			if (status < 0) {
1080e5a1ecc9SSiva Rebbagondla 				rsi_dbg(ERR_ZONE,
1081e5a1ecc9SSiva Rebbagondla 					"Failed to load chunk %d\n", cnt);
1082e5a1ecc9SSiva Rebbagondla 				break;
1083e5a1ecc9SSiva Rebbagondla 			}
1084e5a1ecc9SSiva Rebbagondla 			fw_p += len;
1085e5a1ecc9SSiva Rebbagondla 			if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
1086e5a1ecc9SSiva Rebbagondla 			    RSI_BL_CTRL_LAST_ENTRY)
1087e5a1ecc9SSiva Rebbagondla 				break;
1088e5a1ecc9SSiva Rebbagondla 			cnt++;
1089e5a1ecc9SSiva Rebbagondla 		} while (1);
1090e5a1ecc9SSiva Rebbagondla 	} else {
1091e5a1ecc9SSiva Rebbagondla 		base_address = metadata_p->address;
1092e5a1ecc9SSiva Rebbagondla 		status = hif_ops->load_data_master_write(adapter,
1093e5a1ecc9SSiva Rebbagondla 							 base_address,
1094e5a1ecc9SSiva Rebbagondla 							 instructions_sz,
1095e5a1ecc9SSiva Rebbagondla 							 block_size,
1096e5a1ecc9SSiva Rebbagondla 							 ta_firmware);
1097e5a1ecc9SSiva Rebbagondla 	}
1098e5a1ecc9SSiva Rebbagondla 	if (status) {
1099e5a1ecc9SSiva Rebbagondla 		rsi_dbg(ERR_ZONE,
1100e5a1ecc9SSiva Rebbagondla 			"%s: Unable to load %s blk\n",
1101e5a1ecc9SSiva Rebbagondla 			__func__, metadata_p->name);
1102e5a1ecc9SSiva Rebbagondla 		goto fail_free_fw;
1103e5a1ecc9SSiva Rebbagondla 	}
1104e5a1ecc9SSiva Rebbagondla 
1105e5a1ecc9SSiva Rebbagondla 	rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n",
1106e5a1ecc9SSiva Rebbagondla 		__func__, metadata_p->name);
1107e5a1ecc9SSiva Rebbagondla 
1108e5a1ecc9SSiva Rebbagondla 	if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
1109e5a1ecc9SSiva Rebbagondla 		if (hif_ops->ta_reset(adapter))
1110e5a1ecc9SSiva Rebbagondla 			rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n");
1111e5a1ecc9SSiva Rebbagondla 	} else {
1112e5a1ecc9SSiva Rebbagondla 		if (bl_cmd(adapter, JUMP_TO_ZERO_PC,
1113e5a1ecc9SSiva Rebbagondla 			   CMD_PASS, "JUMP_TO_ZERO") < 0)
1114e5a1ecc9SSiva Rebbagondla 			rsi_dbg(INFO_ZONE, "Jump to zero command failed\n");
1115e5a1ecc9SSiva Rebbagondla 		else
1116e5a1ecc9SSiva Rebbagondla 			rsi_dbg(INFO_ZONE, "Jump to zero command successful\n");
1117e5a1ecc9SSiva Rebbagondla 	}
1118e5a1ecc9SSiva Rebbagondla 
1119e5a1ecc9SSiva Rebbagondla fail_free_fw:
1120e5a1ecc9SSiva Rebbagondla 	kfree(ta_firmware);
1121e5a1ecc9SSiva Rebbagondla fail_release_fw:
1122e5a1ecc9SSiva Rebbagondla 	release_firmware(fw_entry);
1123e5a1ecc9SSiva Rebbagondla 
1124e5a1ecc9SSiva Rebbagondla 	return status;
1125e5a1ecc9SSiva Rebbagondla }
1126e5a1ecc9SSiva Rebbagondla 
1127b78e91bcSPrameela Rani Garnepudi int rsi_hal_device_init(struct rsi_hw *adapter)
1128b78e91bcSPrameela Rani Garnepudi {
1129b78e91bcSPrameela Rani Garnepudi 	struct rsi_common *common = adapter->priv;
11303ac61578SSiva Rebbagondla 	int status;
1131b78e91bcSPrameela Rani Garnepudi 
1132b78e91bcSPrameela Rani Garnepudi 	switch (adapter->device_model) {
1133b78e91bcSPrameela Rani Garnepudi 	case RSI_DEV_9113:
11343ac61578SSiva Rebbagondla 		status = rsi_hal_prepare_fwload(adapter);
11353ac61578SSiva Rebbagondla 		if (status < 0)
11363ac61578SSiva Rebbagondla 			return status;
11373ac61578SSiva Rebbagondla 		if (rsi_load_9113_firmware(adapter)) {
1138b78e91bcSPrameela Rani Garnepudi 			rsi_dbg(ERR_ZONE,
1139b78e91bcSPrameela Rani Garnepudi 				"%s: Failed to load TA instructions\n",
1140b78e91bcSPrameela Rani Garnepudi 				__func__);
1141b78e91bcSPrameela Rani Garnepudi 			return -EINVAL;
1142b78e91bcSPrameela Rani Garnepudi 		}
1143b78e91bcSPrameela Rani Garnepudi 		break;
1144e5a1ecc9SSiva Rebbagondla 	case RSI_DEV_9116:
1145e5a1ecc9SSiva Rebbagondla 		status = rsi_hal_prepare_fwload(adapter);
1146e5a1ecc9SSiva Rebbagondla 		if (status < 0)
1147e5a1ecc9SSiva Rebbagondla 			return status;
1148e5a1ecc9SSiva Rebbagondla 		if (rsi_load_9116_firmware(adapter)) {
1149e5a1ecc9SSiva Rebbagondla 			rsi_dbg(ERR_ZONE,
1150e5a1ecc9SSiva Rebbagondla 				"%s: Failed to load firmware to 9116 device\n",
1151e5a1ecc9SSiva Rebbagondla 				__func__);
1152e5a1ecc9SSiva Rebbagondla 			return -EINVAL;
1153e5a1ecc9SSiva Rebbagondla 		}
1154e5a1ecc9SSiva Rebbagondla 		break;
1155b78e91bcSPrameela Rani Garnepudi 	default:
1156b78e91bcSPrameela Rani Garnepudi 		return -EINVAL;
1157b78e91bcSPrameela Rani Garnepudi 	}
1158015e3674SPrameela Rani Garnepudi 	common->fsm_state = FSM_CARD_NOT_READY;
1159b78e91bcSPrameela Rani Garnepudi 
1160b78e91bcSPrameela Rani Garnepudi 	return 0;
1161b78e91bcSPrameela Rani Garnepudi }
1162b78e91bcSPrameela Rani Garnepudi EXPORT_SYMBOL_GPL(rsi_hal_device_init);
1163b78e91bcSPrameela Rani Garnepudi 
1164