1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2014 Redpine Signals Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
5*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
6*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/firmware.h>
18*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
19*4882a593Smuzhiyun #include "rsi_mgmt.h"
20*4882a593Smuzhiyun #include "rsi_hal.h"
21*4882a593Smuzhiyun #include "rsi_sdio.h"
22*4882a593Smuzhiyun #include "rsi_common.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* FLASH Firmware */
25*4882a593Smuzhiyun static struct ta_metadata metadata_flash_content[] = {
26*4882a593Smuzhiyun {"flash_content", 0x00010000},
27*4882a593Smuzhiyun {"rsi/rs9113_wlan_qspi.rps", 0x00010000},
28*4882a593Smuzhiyun {"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
29*4882a593Smuzhiyun {"flash_content", 0x00010000},
30*4882a593Smuzhiyun {"rsi/rs9113_ap_bt_dual_mode.rps", 0x00010000},
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun static struct ta_metadata metadata[] = {{"pmemdata_dummy", 0x00000000},
35*4882a593Smuzhiyun {"rsi/rs9116_wlan.rps", 0x00000000},
36*4882a593Smuzhiyun {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000},
37*4882a593Smuzhiyun {"rsi/pmemdata_dummy", 0x00000000},
38*4882a593Smuzhiyun {"rsi/rs9116_wlan_bt_classic.rps", 0x00000000}
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
rsi_send_pkt_to_bus(struct rsi_common * common,struct sk_buff * skb)41*4882a593Smuzhiyun int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
44*4882a593Smuzhiyun int status;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun if (common->coex_mode > 1)
47*4882a593Smuzhiyun mutex_lock(&common->tx_bus_mutex);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun status = adapter->host_intf_ops->write_pkt(common->priv,
50*4882a593Smuzhiyun skb->data, skb->len);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun if (common->coex_mode > 1)
53*4882a593Smuzhiyun mutex_unlock(&common->tx_bus_mutex);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun return status;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
rsi_prepare_mgmt_desc(struct rsi_common * common,struct sk_buff * skb)58*4882a593Smuzhiyun int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
61*4882a593Smuzhiyun struct ieee80211_hdr *wh = NULL;
62*4882a593Smuzhiyun struct ieee80211_tx_info *info;
63*4882a593Smuzhiyun struct ieee80211_conf *conf = &adapter->hw->conf;
64*4882a593Smuzhiyun struct ieee80211_vif *vif;
65*4882a593Smuzhiyun struct rsi_mgmt_desc *mgmt_desc;
66*4882a593Smuzhiyun struct skb_info *tx_params;
67*4882a593Smuzhiyun struct rsi_xtended_desc *xtend_desc = NULL;
68*4882a593Smuzhiyun u8 header_size;
69*4882a593Smuzhiyun u32 dword_align_bytes = 0;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (skb->len > MAX_MGMT_PKT_SIZE) {
72*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__);
73*4882a593Smuzhiyun return -EINVAL;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun info = IEEE80211_SKB_CB(skb);
77*4882a593Smuzhiyun tx_params = (struct skb_info *)info->driver_data;
78*4882a593Smuzhiyun vif = tx_params->vif;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Update header size */
81*4882a593Smuzhiyun header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc);
82*4882a593Smuzhiyun if (header_size > skb_headroom(skb)) {
83*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
84*4882a593Smuzhiyun "%s: Failed to add extended descriptor\n",
85*4882a593Smuzhiyun __func__);
86*4882a593Smuzhiyun return -ENOSPC;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun skb_push(skb, header_size);
89*4882a593Smuzhiyun dword_align_bytes = ((unsigned long)skb->data & 0x3f);
90*4882a593Smuzhiyun if (dword_align_bytes > skb_headroom(skb)) {
91*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
92*4882a593Smuzhiyun "%s: Failed to add dword align\n", __func__);
93*4882a593Smuzhiyun return -ENOSPC;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun skb_push(skb, dword_align_bytes);
96*4882a593Smuzhiyun header_size += dword_align_bytes;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun tx_params->internal_hdr_size = header_size;
99*4882a593Smuzhiyun memset(&skb->data[0], 0, header_size);
100*4882a593Smuzhiyun wh = (struct ieee80211_hdr *)&skb->data[header_size];
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun mgmt_desc = (struct rsi_mgmt_desc *)skb->data;
103*4882a593Smuzhiyun xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
106*4882a593Smuzhiyun RSI_WIFI_MGMT_Q);
107*4882a593Smuzhiyun mgmt_desc->frame_type = TX_DOT11_MGMT;
108*4882a593Smuzhiyun mgmt_desc->header_len = MIN_802_11_HDR_LEN;
109*4882a593Smuzhiyun mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (ieee80211_is_probe_req(wh->frame_control))
112*4882a593Smuzhiyun mgmt_desc->frame_info = cpu_to_le16(RSI_INSERT_SEQ_IN_FW);
113*4882a593Smuzhiyun mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE);
114*4882a593Smuzhiyun if (is_broadcast_ether_addr(wh->addr1))
115*4882a593Smuzhiyun mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun mgmt_desc->seq_ctrl =
118*4882a593Smuzhiyun cpu_to_le16(IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)));
119*4882a593Smuzhiyun if ((common->band == NL80211_BAND_2GHZ) && !common->p2p_enabled)
120*4882a593Smuzhiyun mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_1);
121*4882a593Smuzhiyun else
122*4882a593Smuzhiyun mgmt_desc->rate_info = cpu_to_le16(RSI_RATE_6);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (conf_is_ht40(conf))
125*4882a593Smuzhiyun mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (ieee80211_is_probe_resp(wh->frame_control)) {
128*4882a593Smuzhiyun mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID |
129*4882a593Smuzhiyun RSI_FETCH_RETRY_CNT_FRM_HST);
130*4882a593Smuzhiyun #define PROBE_RESP_RETRY_CNT 3
131*4882a593Smuzhiyun xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (((vif->type == NL80211_IFTYPE_AP) ||
135*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_GO)) &&
136*4882a593Smuzhiyun (ieee80211_is_action(wh->frame_control))) {
137*4882a593Smuzhiyun struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (rsta)
140*4882a593Smuzhiyun mgmt_desc->sta_id = tx_params->sta_id;
141*4882a593Smuzhiyun else
142*4882a593Smuzhiyun return -EINVAL;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun mgmt_desc->rate_info |=
145*4882a593Smuzhiyun cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) &
146*4882a593Smuzhiyun RSI_DESC_VAP_ID_MASK);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* This function prepares descriptor for given data packet */
rsi_prepare_data_desc(struct rsi_common * common,struct sk_buff * skb)152*4882a593Smuzhiyun int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
155*4882a593Smuzhiyun struct ieee80211_vif *vif;
156*4882a593Smuzhiyun struct ieee80211_hdr *wh = NULL;
157*4882a593Smuzhiyun struct ieee80211_tx_info *info;
158*4882a593Smuzhiyun struct skb_info *tx_params;
159*4882a593Smuzhiyun struct rsi_data_desc *data_desc;
160*4882a593Smuzhiyun struct rsi_xtended_desc *xtend_desc;
161*4882a593Smuzhiyun u8 ieee80211_size = MIN_802_11_HDR_LEN;
162*4882a593Smuzhiyun u8 header_size;
163*4882a593Smuzhiyun u8 vap_id = 0;
164*4882a593Smuzhiyun u8 dword_align_bytes;
165*4882a593Smuzhiyun u16 seq_num;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun info = IEEE80211_SKB_CB(skb);
168*4882a593Smuzhiyun vif = info->control.vif;
169*4882a593Smuzhiyun tx_params = (struct skb_info *)info->driver_data;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun header_size = FRAME_DESC_SZ + sizeof(struct rsi_xtended_desc);
172*4882a593Smuzhiyun if (header_size > skb_headroom(skb)) {
173*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__);
174*4882a593Smuzhiyun return -ENOSPC;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun skb_push(skb, header_size);
177*4882a593Smuzhiyun dword_align_bytes = ((unsigned long)skb->data & 0x3f);
178*4882a593Smuzhiyun if (header_size > skb_headroom(skb)) {
179*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
180*4882a593Smuzhiyun return -ENOSPC;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun skb_push(skb, dword_align_bytes);
183*4882a593Smuzhiyun header_size += dword_align_bytes;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun tx_params->internal_hdr_size = header_size;
186*4882a593Smuzhiyun data_desc = (struct rsi_data_desc *)skb->data;
187*4882a593Smuzhiyun memset(data_desc, 0, header_size);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
190*4882a593Smuzhiyun wh = (struct ieee80211_hdr *)&skb->data[header_size];
191*4882a593Smuzhiyun seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl));
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (ieee80211_is_data_qos(wh->frame_control)) {
196*4882a593Smuzhiyun ieee80211_size += 2;
197*4882a593Smuzhiyun data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (((vif->type == NL80211_IFTYPE_STATION) ||
201*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_CLIENT)) &&
202*4882a593Smuzhiyun (adapter->ps_state == PS_ENABLED))
203*4882a593Smuzhiyun wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) &&
206*4882a593Smuzhiyun tx_params->have_key) {
207*4882a593Smuzhiyun if (rsi_is_cipher_wep(common))
208*4882a593Smuzhiyun ieee80211_size += 4;
209*4882a593Smuzhiyun else
210*4882a593Smuzhiyun ieee80211_size += 8;
211*4882a593Smuzhiyun data_desc->mac_flags |= cpu_to_le16(RSI_ENCRYPT_PKT);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun rsi_set_len_qno(&data_desc->len_qno, (skb->len - FRAME_DESC_SZ),
214*4882a593Smuzhiyun RSI_WIFI_DATA_Q);
215*4882a593Smuzhiyun data_desc->header_len = ieee80211_size;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (common->rate_config[common->band].fixed_enabled) {
218*4882a593Smuzhiyun /* Send fixed rate */
219*4882a593Smuzhiyun u16 fixed_rate = common->rate_config[common->band].fixed_hw_rate;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
222*4882a593Smuzhiyun data_desc->rate_info = cpu_to_le16(fixed_rate);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (conf_is_ht40(&common->priv->hw->conf))
225*4882a593Smuzhiyun data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun if (common->vif_info[0].sgi && (fixed_rate & 0x100)) {
228*4882a593Smuzhiyun /* Only MCS rates */
229*4882a593Smuzhiyun data_desc->rate_info |=
230*4882a593Smuzhiyun cpu_to_le16(ENABLE_SHORTGI_RATE);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
235*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n");
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
238*4882a593Smuzhiyun if (common->band == NL80211_BAND_5GHZ)
239*4882a593Smuzhiyun data_desc->rate_info = cpu_to_le16(RSI_RATE_6);
240*4882a593Smuzhiyun else
241*4882a593Smuzhiyun data_desc->rate_info = cpu_to_le16(RSI_RATE_1);
242*4882a593Smuzhiyun data_desc->mac_flags |= cpu_to_le16(RSI_REKEY_PURPOSE);
243*4882a593Smuzhiyun data_desc->misc_flags |= RSI_FETCH_RETRY_CNT_FRM_HST;
244*4882a593Smuzhiyun #define EAPOL_RETRY_CNT 15
245*4882a593Smuzhiyun xtend_desc->retry_cnt = EAPOL_RETRY_CNT;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (common->eapol4_confirm)
248*4882a593Smuzhiyun skb->priority = VO_Q;
249*4882a593Smuzhiyun else
250*4882a593Smuzhiyun rsi_set_len_qno(&data_desc->len_qno,
251*4882a593Smuzhiyun (skb->len - FRAME_DESC_SZ),
252*4882a593Smuzhiyun RSI_WIFI_MGMT_Q);
253*4882a593Smuzhiyun if (((skb->len - header_size) == EAPOL4_PACKET_LEN) ||
254*4882a593Smuzhiyun ((skb->len - header_size) == EAPOL4_PACKET_LEN - 2)) {
255*4882a593Smuzhiyun data_desc->misc_flags |=
256*4882a593Smuzhiyun RSI_DESC_REQUIRE_CFM_TO_HOST;
257*4882a593Smuzhiyun xtend_desc->confirm_frame_type = EAPOL4_CONFIRM;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun data_desc->mac_flags |= cpu_to_le16(seq_num & 0xfff);
262*4882a593Smuzhiyun data_desc->qid_tid = ((skb->priority & 0xf) |
263*4882a593Smuzhiyun ((tx_params->tid & 0xf) << 4));
264*4882a593Smuzhiyun data_desc->sta_id = tx_params->sta_id;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if ((is_broadcast_ether_addr(wh->addr1)) ||
267*4882a593Smuzhiyun (is_multicast_ether_addr(wh->addr1))) {
268*4882a593Smuzhiyun data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE);
269*4882a593Smuzhiyun data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT);
270*4882a593Smuzhiyun data_desc->sta_id = vap_id;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if ((vif->type == NL80211_IFTYPE_AP) ||
273*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_GO)) {
274*4882a593Smuzhiyun if (common->band == NL80211_BAND_5GHZ)
275*4882a593Smuzhiyun data_desc->rate_info = cpu_to_le16(RSI_RATE_6);
276*4882a593Smuzhiyun else
277*4882a593Smuzhiyun data_desc->rate_info = cpu_to_le16(RSI_RATE_1);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun if (((vif->type == NL80211_IFTYPE_AP) ||
281*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_GO)) &&
282*4882a593Smuzhiyun (ieee80211_has_moredata(wh->frame_control)))
283*4882a593Smuzhiyun data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun data_desc->rate_info |=
286*4882a593Smuzhiyun cpu_to_le16((tx_params->vap_id << RSI_DESC_VAP_ID_OFST) &
287*4882a593Smuzhiyun RSI_DESC_VAP_ID_MASK);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /* This function sends received data packet from driver to device */
rsi_send_data_pkt(struct rsi_common * common,struct sk_buff * skb)293*4882a593Smuzhiyun int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
296*4882a593Smuzhiyun struct ieee80211_vif *vif;
297*4882a593Smuzhiyun struct ieee80211_tx_info *info;
298*4882a593Smuzhiyun struct ieee80211_bss_conf *bss;
299*4882a593Smuzhiyun int status = -EINVAL;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (!skb)
302*4882a593Smuzhiyun return 0;
303*4882a593Smuzhiyun if (common->iface_down)
304*4882a593Smuzhiyun goto err;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun info = IEEE80211_SKB_CB(skb);
307*4882a593Smuzhiyun if (!info->control.vif)
308*4882a593Smuzhiyun goto err;
309*4882a593Smuzhiyun vif = info->control.vif;
310*4882a593Smuzhiyun bss = &vif->bss_conf;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (((vif->type == NL80211_IFTYPE_STATION) ||
313*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_CLIENT)) &&
314*4882a593Smuzhiyun (!bss->assoc))
315*4882a593Smuzhiyun goto err;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun status = rsi_send_pkt_to_bus(common, skb);
318*4882a593Smuzhiyun if (status)
319*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun err:
322*4882a593Smuzhiyun ++common->tx_stats.total_tx_pkt_freed[skb->priority];
323*4882a593Smuzhiyun rsi_indicate_tx_status(adapter, skb, status);
324*4882a593Smuzhiyun return status;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /**
328*4882a593Smuzhiyun * rsi_send_mgmt_pkt() - This functions sends the received management packet
329*4882a593Smuzhiyun * from driver to device.
330*4882a593Smuzhiyun * @common: Pointer to the driver private structure.
331*4882a593Smuzhiyun * @skb: Pointer to the socket buffer structure.
332*4882a593Smuzhiyun *
333*4882a593Smuzhiyun * Return: status: 0 on success, -1 on failure.
334*4882a593Smuzhiyun */
rsi_send_mgmt_pkt(struct rsi_common * common,struct sk_buff * skb)335*4882a593Smuzhiyun int rsi_send_mgmt_pkt(struct rsi_common *common,
336*4882a593Smuzhiyun struct sk_buff *skb)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun struct rsi_hw *adapter = common->priv;
339*4882a593Smuzhiyun struct ieee80211_bss_conf *bss;
340*4882a593Smuzhiyun struct ieee80211_hdr *wh;
341*4882a593Smuzhiyun struct ieee80211_tx_info *info;
342*4882a593Smuzhiyun struct skb_info *tx_params;
343*4882a593Smuzhiyun struct rsi_mgmt_desc *mgmt_desc;
344*4882a593Smuzhiyun struct rsi_xtended_desc *xtend_desc;
345*4882a593Smuzhiyun int status = -E2BIG;
346*4882a593Smuzhiyun u8 header_size;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun info = IEEE80211_SKB_CB(skb);
349*4882a593Smuzhiyun tx_params = (struct skb_info *)info->driver_data;
350*4882a593Smuzhiyun header_size = tx_params->internal_hdr_size;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (tx_params->flags & INTERNAL_MGMT_PKT) {
353*4882a593Smuzhiyun status = adapter->host_intf_ops->write_pkt(common->priv,
354*4882a593Smuzhiyun (u8 *)skb->data,
355*4882a593Smuzhiyun skb->len);
356*4882a593Smuzhiyun if (status) {
357*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
358*4882a593Smuzhiyun "%s: Failed to write the packet\n", __func__);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun dev_kfree_skb(skb);
361*4882a593Smuzhiyun return status;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun bss = &info->control.vif->bss_conf;
365*4882a593Smuzhiyun wh = (struct ieee80211_hdr *)&skb->data[header_size];
366*4882a593Smuzhiyun mgmt_desc = (struct rsi_mgmt_desc *)skb->data;
367*4882a593Smuzhiyun xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ];
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /* Indicate to firmware to give cfm for probe */
370*4882a593Smuzhiyun if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) {
371*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
372*4882a593Smuzhiyun "%s: blocking mgmt queue\n", __func__);
373*4882a593Smuzhiyun mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST;
374*4882a593Smuzhiyun xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM;
375*4882a593Smuzhiyun common->mgmt_q_block = true;
376*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n");
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun status = rsi_send_pkt_to_bus(common, skb);
380*4882a593Smuzhiyun if (status)
381*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun rsi_indicate_tx_status(common->priv, skb, status);
384*4882a593Smuzhiyun return status;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
rsi_send_bt_pkt(struct rsi_common * common,struct sk_buff * skb)387*4882a593Smuzhiyun int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun int status = -EINVAL;
390*4882a593Smuzhiyun u8 header_size = 0;
391*4882a593Smuzhiyun struct rsi_bt_desc *bt_desc;
392*4882a593Smuzhiyun u8 queueno = ((skb->data[1] >> 4) & 0xf);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun if (queueno == RSI_BT_MGMT_Q) {
395*4882a593Smuzhiyun status = rsi_send_pkt_to_bus(common, skb);
396*4882a593Smuzhiyun if (status)
397*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
398*4882a593Smuzhiyun __func__);
399*4882a593Smuzhiyun goto out;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun header_size = FRAME_DESC_SZ;
402*4882a593Smuzhiyun if (header_size > skb_headroom(skb)) {
403*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
404*4882a593Smuzhiyun status = -ENOSPC;
405*4882a593Smuzhiyun goto out;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun skb_push(skb, header_size);
408*4882a593Smuzhiyun memset(skb->data, 0, header_size);
409*4882a593Smuzhiyun bt_desc = (struct rsi_bt_desc *)skb->data;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
412*4882a593Smuzhiyun RSI_BT_DATA_Q);
413*4882a593Smuzhiyun bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun status = rsi_send_pkt_to_bus(common, skb);
416*4882a593Smuzhiyun if (status)
417*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun out:
420*4882a593Smuzhiyun dev_kfree_skb(skb);
421*4882a593Smuzhiyun return status;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
rsi_prepare_beacon(struct rsi_common * common,struct sk_buff * skb)424*4882a593Smuzhiyun int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
427*4882a593Smuzhiyun struct rsi_data_desc *bcn_frm;
428*4882a593Smuzhiyun struct ieee80211_hw *hw = common->priv->hw;
429*4882a593Smuzhiyun struct ieee80211_conf *conf = &hw->conf;
430*4882a593Smuzhiyun struct ieee80211_vif *vif;
431*4882a593Smuzhiyun struct sk_buff *mac_bcn;
432*4882a593Smuzhiyun u8 vap_id = 0, i;
433*4882a593Smuzhiyun u16 tim_offset = 0;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun for (i = 0; i < RSI_MAX_VIFS; i++) {
436*4882a593Smuzhiyun vif = adapter->vifs[i];
437*4882a593Smuzhiyun if (!vif)
438*4882a593Smuzhiyun continue;
439*4882a593Smuzhiyun if ((vif->type == NL80211_IFTYPE_AP) ||
440*4882a593Smuzhiyun (vif->type == NL80211_IFTYPE_P2P_GO))
441*4882a593Smuzhiyun break;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun if (!vif)
444*4882a593Smuzhiyun return -EINVAL;
445*4882a593Smuzhiyun mac_bcn = ieee80211_beacon_get_tim(adapter->hw,
446*4882a593Smuzhiyun vif,
447*4882a593Smuzhiyun &tim_offset, NULL);
448*4882a593Smuzhiyun if (!mac_bcn) {
449*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n");
450*4882a593Smuzhiyun return -EINVAL;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun common->beacon_cnt++;
454*4882a593Smuzhiyun bcn_frm = (struct rsi_data_desc *)skb->data;
455*4882a593Smuzhiyun rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q);
456*4882a593Smuzhiyun bcn_frm->header_len = MIN_802_11_HDR_LEN;
457*4882a593Smuzhiyun bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO |
458*4882a593Smuzhiyun RSI_DATA_DESC_NO_ACK_IND |
459*4882a593Smuzhiyun RSI_DATA_DESC_BEACON_FRAME |
460*4882a593Smuzhiyun RSI_DATA_DESC_INSERT_TSF |
461*4882a593Smuzhiyun RSI_DATA_DESC_INSERT_SEQ_NO |
462*4882a593Smuzhiyun RATE_INFO_ENABLE);
463*4882a593Smuzhiyun bcn_frm->rate_info = cpu_to_le16(vap_id << 14);
464*4882a593Smuzhiyun bcn_frm->qid_tid = BEACON_HW_Q;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun if (conf_is_ht40_plus(conf)) {
467*4882a593Smuzhiyun bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE);
468*4882a593Smuzhiyun bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12);
469*4882a593Smuzhiyun } else if (conf_is_ht40_minus(conf)) {
470*4882a593Smuzhiyun bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE);
471*4882a593Smuzhiyun bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun if (common->band == NL80211_BAND_2GHZ)
475*4882a593Smuzhiyun bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1);
476*4882a593Smuzhiyun else
477*4882a593Smuzhiyun bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (mac_bcn->data[tim_offset + 2] == 0)
480*4882a593Smuzhiyun bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len);
483*4882a593Smuzhiyun skb_put(skb, mac_bcn->len + FRAME_DESC_SZ);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun dev_kfree_skb(mac_bcn);
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
bl_cmd_timeout(struct timer_list * t)490*4882a593Smuzhiyun static void bl_cmd_timeout(struct timer_list *t)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct rsi_hw *adapter = from_timer(adapter, t, bl_cmd_timer);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun adapter->blcmd_timer_expired = true;
495*4882a593Smuzhiyun del_timer(&adapter->bl_cmd_timer);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
bl_start_cmd_timer(struct rsi_hw * adapter,u32 timeout)498*4882a593Smuzhiyun static int bl_start_cmd_timer(struct rsi_hw *adapter, u32 timeout)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun timer_setup(&adapter->bl_cmd_timer, bl_cmd_timeout, 0);
501*4882a593Smuzhiyun adapter->bl_cmd_timer.expires = (msecs_to_jiffies(timeout) + jiffies);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun adapter->blcmd_timer_expired = false;
504*4882a593Smuzhiyun add_timer(&adapter->bl_cmd_timer);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun return 0;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
bl_stop_cmd_timer(struct rsi_hw * adapter)509*4882a593Smuzhiyun static int bl_stop_cmd_timer(struct rsi_hw *adapter)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun adapter->blcmd_timer_expired = false;
512*4882a593Smuzhiyun if (timer_pending(&adapter->bl_cmd_timer))
513*4882a593Smuzhiyun del_timer(&adapter->bl_cmd_timer);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
bl_write_cmd(struct rsi_hw * adapter,u8 cmd,u8 exp_resp,u16 * cmd_resp)518*4882a593Smuzhiyun static int bl_write_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp,
519*4882a593Smuzhiyun u16 *cmd_resp)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
522*4882a593Smuzhiyun u32 regin_val = 0, regout_val = 0;
523*4882a593Smuzhiyun u32 regin_input = 0;
524*4882a593Smuzhiyun u8 output = 0;
525*4882a593Smuzhiyun int status;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun regin_input = (REGIN_INPUT | adapter->priv->coex_mode);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun while (!adapter->blcmd_timer_expired) {
530*4882a593Smuzhiyun regin_val = 0;
531*4882a593Smuzhiyun status = hif_ops->master_reg_read(adapter, SWBL_REGIN,
532*4882a593Smuzhiyun ®in_val, 2);
533*4882a593Smuzhiyun if (status < 0) {
534*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
535*4882a593Smuzhiyun "%s: Command %0x REGIN reading failed..\n",
536*4882a593Smuzhiyun __func__, cmd);
537*4882a593Smuzhiyun return status;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun mdelay(1);
540*4882a593Smuzhiyun if ((regin_val >> 12) != REGIN_VALID)
541*4882a593Smuzhiyun break;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun if (adapter->blcmd_timer_expired) {
544*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
545*4882a593Smuzhiyun "%s: Command %0x REGIN reading timed out..\n",
546*4882a593Smuzhiyun __func__, cmd);
547*4882a593Smuzhiyun return -ETIMEDOUT;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
551*4882a593Smuzhiyun "Issuing write to Regin val:%0x sending cmd:%0x\n",
552*4882a593Smuzhiyun regin_val, (cmd | regin_input << 8));
553*4882a593Smuzhiyun status = hif_ops->master_reg_write(adapter, SWBL_REGIN,
554*4882a593Smuzhiyun (cmd | regin_input << 8), 2);
555*4882a593Smuzhiyun if (status < 0)
556*4882a593Smuzhiyun return status;
557*4882a593Smuzhiyun mdelay(1);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun if (cmd == LOAD_HOSTED_FW || cmd == JUMP_TO_ZERO_PC) {
560*4882a593Smuzhiyun /* JUMP_TO_ZERO_PC doesn't expect
561*4882a593Smuzhiyun * any response. So return from here
562*4882a593Smuzhiyun */
563*4882a593Smuzhiyun return 0;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun while (!adapter->blcmd_timer_expired) {
567*4882a593Smuzhiyun regout_val = 0;
568*4882a593Smuzhiyun status = hif_ops->master_reg_read(adapter, SWBL_REGOUT,
569*4882a593Smuzhiyun ®out_val, 2);
570*4882a593Smuzhiyun if (status < 0) {
571*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
572*4882a593Smuzhiyun "%s: Command %0x REGOUT reading failed..\n",
573*4882a593Smuzhiyun __func__, cmd);
574*4882a593Smuzhiyun return status;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun mdelay(1);
577*4882a593Smuzhiyun if ((regout_val >> 8) == REGOUT_VALID)
578*4882a593Smuzhiyun break;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun if (adapter->blcmd_timer_expired) {
581*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
582*4882a593Smuzhiyun "%s: Command %0x REGOUT reading timed out..\n",
583*4882a593Smuzhiyun __func__, cmd);
584*4882a593Smuzhiyun return status;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun *cmd_resp = ((u16 *)®out_val)[0] & 0xffff;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun output = ((u8 *)®out_val)[0] & 0xff;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun status = hif_ops->master_reg_write(adapter, SWBL_REGOUT,
592*4882a593Smuzhiyun (cmd | REGOUT_INVALID << 8), 2);
593*4882a593Smuzhiyun if (status < 0) {
594*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
595*4882a593Smuzhiyun "%s: Command %0x REGOUT writing failed..\n",
596*4882a593Smuzhiyun __func__, cmd);
597*4882a593Smuzhiyun return status;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun mdelay(1);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun if (output != exp_resp) {
602*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
603*4882a593Smuzhiyun "%s: Recvd resp %x for cmd %0x\n",
604*4882a593Smuzhiyun __func__, output, cmd);
605*4882a593Smuzhiyun return -EINVAL;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
608*4882a593Smuzhiyun "%s: Recvd Expected resp %x for cmd %0x\n",
609*4882a593Smuzhiyun __func__, output, cmd);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun return 0;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
bl_cmd(struct rsi_hw * adapter,u8 cmd,u8 exp_resp,char * str)614*4882a593Smuzhiyun static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun u16 regout_val = 0;
617*4882a593Smuzhiyun u32 timeout;
618*4882a593Smuzhiyun int status;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if ((cmd == EOF_REACHED) || (cmd == PING_VALID) || (cmd == PONG_VALID))
621*4882a593Smuzhiyun timeout = BL_BURN_TIMEOUT;
622*4882a593Smuzhiyun else
623*4882a593Smuzhiyun timeout = BL_CMD_TIMEOUT;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun bl_start_cmd_timer(adapter, timeout);
626*4882a593Smuzhiyun status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val);
627*4882a593Smuzhiyun if (status < 0) {
628*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
629*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
630*4882a593Smuzhiyun "%s: Command %s (%0x) writing failed..\n",
631*4882a593Smuzhiyun __func__, str, cmd);
632*4882a593Smuzhiyun return status;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
635*4882a593Smuzhiyun return 0;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun #define CHECK_SUM_OFFSET 20
639*4882a593Smuzhiyun #define LEN_OFFSET 8
640*4882a593Smuzhiyun #define ADDR_OFFSET 16
bl_write_header(struct rsi_hw * adapter,u8 * flash_content,u32 content_size)641*4882a593Smuzhiyun static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
642*4882a593Smuzhiyun u32 content_size)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
645*4882a593Smuzhiyun struct bl_header *bl_hdr;
646*4882a593Smuzhiyun u32 write_addr, write_len;
647*4882a593Smuzhiyun int status;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL);
650*4882a593Smuzhiyun if (!bl_hdr)
651*4882a593Smuzhiyun return -ENOMEM;
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun bl_hdr->flags = 0;
654*4882a593Smuzhiyun bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode);
655*4882a593Smuzhiyun bl_hdr->check_sum =
656*4882a593Smuzhiyun cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]);
657*4882a593Smuzhiyun bl_hdr->flash_start_address =
658*4882a593Smuzhiyun cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]);
659*4882a593Smuzhiyun bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]);
660*4882a593Smuzhiyun write_len = sizeof(struct bl_header);
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
663*4882a593Smuzhiyun write_addr = PING_BUFFER_ADDRESS;
664*4882a593Smuzhiyun status = hif_ops->write_reg_multiple(adapter, write_addr,
665*4882a593Smuzhiyun (u8 *)bl_hdr, write_len);
666*4882a593Smuzhiyun if (status < 0) {
667*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
668*4882a593Smuzhiyun "%s: Failed to load Version/CRC structure\n",
669*4882a593Smuzhiyun __func__);
670*4882a593Smuzhiyun goto fail;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun } else {
673*4882a593Smuzhiyun write_addr = PING_BUFFER_ADDRESS >> 16;
674*4882a593Smuzhiyun status = hif_ops->master_access_msword(adapter, write_addr);
675*4882a593Smuzhiyun if (status < 0) {
676*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
677*4882a593Smuzhiyun "%s: Unable to set ms word to common reg\n",
678*4882a593Smuzhiyun __func__);
679*4882a593Smuzhiyun goto fail;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun write_addr = RSI_SD_REQUEST_MASTER |
682*4882a593Smuzhiyun (PING_BUFFER_ADDRESS & 0xFFFF);
683*4882a593Smuzhiyun status = hif_ops->write_reg_multiple(adapter, write_addr,
684*4882a593Smuzhiyun (u8 *)bl_hdr, write_len);
685*4882a593Smuzhiyun if (status < 0) {
686*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
687*4882a593Smuzhiyun "%s: Failed to load Version/CRC structure\n",
688*4882a593Smuzhiyun __func__);
689*4882a593Smuzhiyun goto fail;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun status = 0;
693*4882a593Smuzhiyun fail:
694*4882a593Smuzhiyun kfree(bl_hdr);
695*4882a593Smuzhiyun return status;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
read_flash_capacity(struct rsi_hw * adapter)698*4882a593Smuzhiyun static u32 read_flash_capacity(struct rsi_hw *adapter)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun u32 flash_sz = 0;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun if ((adapter->host_intf_ops->master_reg_read(adapter, FLASH_SIZE_ADDR,
703*4882a593Smuzhiyun &flash_sz, 2)) < 0) {
704*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
705*4882a593Smuzhiyun "%s: Flash size reading failed..\n",
706*4882a593Smuzhiyun __func__);
707*4882a593Smuzhiyun return 0;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "Flash capacity: %d KiloBytes\n", flash_sz);
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun return (flash_sz * 1024); /* Return size in kbytes */
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
ping_pong_write(struct rsi_hw * adapter,u8 cmd,u8 * addr,u32 size)714*4882a593Smuzhiyun static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
717*4882a593Smuzhiyun u32 block_size = adapter->block_size;
718*4882a593Smuzhiyun u32 cmd_addr;
719*4882a593Smuzhiyun u16 cmd_resp, cmd_req;
720*4882a593Smuzhiyun u8 *str;
721*4882a593Smuzhiyun int status;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (cmd == PING_WRITE) {
724*4882a593Smuzhiyun cmd_addr = PING_BUFFER_ADDRESS;
725*4882a593Smuzhiyun cmd_resp = PONG_AVAIL;
726*4882a593Smuzhiyun cmd_req = PING_VALID;
727*4882a593Smuzhiyun str = "PING_VALID";
728*4882a593Smuzhiyun } else {
729*4882a593Smuzhiyun cmd_addr = PONG_BUFFER_ADDRESS;
730*4882a593Smuzhiyun cmd_resp = PING_AVAIL;
731*4882a593Smuzhiyun cmd_req = PONG_VALID;
732*4882a593Smuzhiyun str = "PONG_VALID";
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun status = hif_ops->load_data_master_write(adapter, cmd_addr, size,
736*4882a593Smuzhiyun block_size, addr);
737*4882a593Smuzhiyun if (status) {
738*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Unable to write blk at addr %0x\n",
739*4882a593Smuzhiyun __func__, *addr);
740*4882a593Smuzhiyun return status;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun status = bl_cmd(adapter, cmd_req, cmd_resp, str);
744*4882a593Smuzhiyun if (status)
745*4882a593Smuzhiyun return status;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun return 0;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
auto_fw_upgrade(struct rsi_hw * adapter,u8 * flash_content,u32 content_size)750*4882a593Smuzhiyun static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content,
751*4882a593Smuzhiyun u32 content_size)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun u8 cmd;
754*4882a593Smuzhiyun u32 temp_content_size, num_flash, index;
755*4882a593Smuzhiyun u32 flash_start_address;
756*4882a593Smuzhiyun int status;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun if (content_size > MAX_FLASH_FILE_SIZE) {
759*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
760*4882a593Smuzhiyun "%s: Flash Content size is more than 400K %u\n",
761*4882a593Smuzhiyun __func__, MAX_FLASH_FILE_SIZE);
762*4882a593Smuzhiyun return -EINVAL;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun flash_start_address = *(u32 *)&flash_content[FLASH_START_ADDRESS];
766*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "flash start address: %08x\n", flash_start_address);
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun if (flash_start_address < FW_IMAGE_MIN_ADDRESS) {
769*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
770*4882a593Smuzhiyun "%s: Fw image Flash Start Address is less than 64K\n",
771*4882a593Smuzhiyun __func__);
772*4882a593Smuzhiyun return -EINVAL;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (flash_start_address % FLASH_SECTOR_SIZE) {
776*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
777*4882a593Smuzhiyun "%s: Flash Start Address is not multiple of 4K\n",
778*4882a593Smuzhiyun __func__);
779*4882a593Smuzhiyun return -EINVAL;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if ((flash_start_address + content_size) > adapter->flash_capacity) {
783*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
784*4882a593Smuzhiyun "%s: Flash Content will cross max flash size\n",
785*4882a593Smuzhiyun __func__);
786*4882a593Smuzhiyun return -EINVAL;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun temp_content_size = content_size;
790*4882a593Smuzhiyun num_flash = content_size / FLASH_WRITE_CHUNK_SIZE;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "content_size: %d, num_flash: %d\n",
793*4882a593Smuzhiyun content_size, num_flash);
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun for (index = 0; index <= num_flash; index++) {
796*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "flash index: %d\n", index);
797*4882a593Smuzhiyun if (index != num_flash) {
798*4882a593Smuzhiyun content_size = FLASH_WRITE_CHUNK_SIZE;
799*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "QSPI content_size:%d\n",
800*4882a593Smuzhiyun content_size);
801*4882a593Smuzhiyun } else {
802*4882a593Smuzhiyun content_size =
803*4882a593Smuzhiyun temp_content_size % FLASH_WRITE_CHUNK_SIZE;
804*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
805*4882a593Smuzhiyun "Writing last sector content_size:%d\n",
806*4882a593Smuzhiyun content_size);
807*4882a593Smuzhiyun if (!content_size) {
808*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "instruction size zero\n");
809*4882a593Smuzhiyun break;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun if (index % 2)
814*4882a593Smuzhiyun cmd = PING_WRITE;
815*4882a593Smuzhiyun else
816*4882a593Smuzhiyun cmd = PONG_WRITE;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun status = ping_pong_write(adapter, cmd, flash_content,
819*4882a593Smuzhiyun content_size);
820*4882a593Smuzhiyun if (status) {
821*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Unable to load %d block\n",
822*4882a593Smuzhiyun __func__, index);
823*4882a593Smuzhiyun return status;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
827*4882a593Smuzhiyun "%s: Successfully loaded %d instructions\n",
828*4882a593Smuzhiyun __func__, index);
829*4882a593Smuzhiyun flash_content += content_size;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL,
833*4882a593Smuzhiyun "EOF_REACHED");
834*4882a593Smuzhiyun if (status)
835*4882a593Smuzhiyun return status;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n");
838*4882a593Smuzhiyun return 0;
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
rsi_hal_prepare_fwload(struct rsi_hw * adapter)841*4882a593Smuzhiyun static int rsi_hal_prepare_fwload(struct rsi_hw *adapter)
842*4882a593Smuzhiyun {
843*4882a593Smuzhiyun struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
844*4882a593Smuzhiyun u32 regout_val = 0;
845*4882a593Smuzhiyun int status;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun while (!adapter->blcmd_timer_expired) {
850*4882a593Smuzhiyun status = hif_ops->master_reg_read(adapter, SWBL_REGOUT,
851*4882a593Smuzhiyun ®out_val,
852*4882a593Smuzhiyun RSI_COMMON_REG_SIZE);
853*4882a593Smuzhiyun if (status < 0) {
854*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
855*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
856*4882a593Smuzhiyun "%s: REGOUT read failed\n", __func__);
857*4882a593Smuzhiyun return status;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun mdelay(1);
860*4882a593Smuzhiyun if ((regout_val >> 8) == REGOUT_VALID)
861*4882a593Smuzhiyun break;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun if (adapter->blcmd_timer_expired) {
864*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: REGOUT read timedout\n", __func__);
865*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
866*4882a593Smuzhiyun "%s: Soft boot loader not present\n", __func__);
867*4882a593Smuzhiyun return -ETIMEDOUT;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Received Board Version Number: %x\n",
872*4882a593Smuzhiyun (regout_val & 0xff));
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun status = hif_ops->master_reg_write(adapter, SWBL_REGOUT,
875*4882a593Smuzhiyun (REGOUT_INVALID |
876*4882a593Smuzhiyun REGOUT_INVALID << 8),
877*4882a593Smuzhiyun RSI_COMMON_REG_SIZE);
878*4882a593Smuzhiyun if (status < 0)
879*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: REGOUT writing failed..\n", __func__);
880*4882a593Smuzhiyun else
881*4882a593Smuzhiyun rsi_dbg(INFO_ZONE,
882*4882a593Smuzhiyun "===> Device is ready to load firmware <===\n");
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun return status;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun
rsi_load_9113_firmware(struct rsi_hw * adapter)887*4882a593Smuzhiyun static int rsi_load_9113_firmware(struct rsi_hw *adapter)
888*4882a593Smuzhiyun {
889*4882a593Smuzhiyun struct rsi_common *common = adapter->priv;
890*4882a593Smuzhiyun const struct firmware *fw_entry = NULL;
891*4882a593Smuzhiyun u32 content_size;
892*4882a593Smuzhiyun u16 tmp_regout_val = 0;
893*4882a593Smuzhiyun struct ta_metadata *metadata_p;
894*4882a593Smuzhiyun int status;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
897*4882a593Smuzhiyun "AUTO_READ_CMD");
898*4882a593Smuzhiyun if (status < 0)
899*4882a593Smuzhiyun return status;
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun adapter->flash_capacity = read_flash_capacity(adapter);
902*4882a593Smuzhiyun if (adapter->flash_capacity <= 0) {
903*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
904*4882a593Smuzhiyun "%s: Unable to read flash size from EEPROM\n",
905*4882a593Smuzhiyun __func__);
906*4882a593Smuzhiyun return -EINVAL;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun metadata_p = &metadata_flash_content[adapter->priv->coex_mode];
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "%s: Loading file %s\n", __func__, metadata_p->name);
912*4882a593Smuzhiyun adapter->fw_file_name = metadata_p->name;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
915*4882a593Smuzhiyun if (status < 0) {
916*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
917*4882a593Smuzhiyun __func__, metadata_p->name);
918*4882a593Smuzhiyun return status;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun content_size = fw_entry->size;
921*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", content_size);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun /* Get the firmware version */
924*4882a593Smuzhiyun common->lmac_ver.ver.info.fw_ver[0] =
925*4882a593Smuzhiyun fw_entry->data[LMAC_VER_OFFSET_9113] & 0xFF;
926*4882a593Smuzhiyun common->lmac_ver.ver.info.fw_ver[1] =
927*4882a593Smuzhiyun fw_entry->data[LMAC_VER_OFFSET_9113 + 1] & 0xFF;
928*4882a593Smuzhiyun common->lmac_ver.major =
929*4882a593Smuzhiyun fw_entry->data[LMAC_VER_OFFSET_9113 + 2] & 0xFF;
930*4882a593Smuzhiyun common->lmac_ver.release_num =
931*4882a593Smuzhiyun fw_entry->data[LMAC_VER_OFFSET_9113 + 3] & 0xFF;
932*4882a593Smuzhiyun common->lmac_ver.minor =
933*4882a593Smuzhiyun fw_entry->data[LMAC_VER_OFFSET_9113 + 4] & 0xFF;
934*4882a593Smuzhiyun common->lmac_ver.patch_num = 0;
935*4882a593Smuzhiyun rsi_print_version(common);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun status = bl_write_header(adapter, (u8 *)fw_entry->data, content_size);
938*4882a593Smuzhiyun if (status) {
939*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
940*4882a593Smuzhiyun "%s: RPS Image header loading failed\n",
941*4882a593Smuzhiyun __func__);
942*4882a593Smuzhiyun goto fail;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun bl_start_cmd_timer(adapter, BL_CMD_TIMEOUT);
946*4882a593Smuzhiyun status = bl_write_cmd(adapter, CHECK_CRC, CMD_PASS, &tmp_regout_val);
947*4882a593Smuzhiyun if (status) {
948*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
949*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
950*4882a593Smuzhiyun "%s: CHECK_CRC Command writing failed..\n",
951*4882a593Smuzhiyun __func__);
952*4882a593Smuzhiyun if ((tmp_regout_val & 0xff) == CMD_FAIL) {
953*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
954*4882a593Smuzhiyun "CRC Fail.. Proceeding to Upgrade mode\n");
955*4882a593Smuzhiyun goto fw_upgrade;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun bl_stop_cmd_timer(adapter);
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun status = bl_cmd(adapter, POLLING_MODE, CMD_PASS, "POLLING_MODE");
961*4882a593Smuzhiyun if (status)
962*4882a593Smuzhiyun goto fail;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun load_image_cmd:
965*4882a593Smuzhiyun status = bl_cmd(adapter, LOAD_HOSTED_FW, LOADING_INITIATED,
966*4882a593Smuzhiyun "LOAD_HOSTED_FW");
967*4882a593Smuzhiyun if (status)
968*4882a593Smuzhiyun goto fail;
969*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Load Image command passed..\n");
970*4882a593Smuzhiyun goto success;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun fw_upgrade:
973*4882a593Smuzhiyun status = bl_cmd(adapter, BURN_HOSTED_FW, SEND_RPS_FILE, "FW_UPGRADE");
974*4882a593Smuzhiyun if (status)
975*4882a593Smuzhiyun goto fail;
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Burn Command Pass.. Upgrading the firmware\n");
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun status = auto_fw_upgrade(adapter, (u8 *)fw_entry->data, content_size);
980*4882a593Smuzhiyun if (status == 0) {
981*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Firmware upgradation Done\n");
982*4882a593Smuzhiyun goto load_image_cmd;
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Firmware upgrade failed\n");
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun status = bl_cmd(adapter, CONFIG_AUTO_READ_MODE, CMD_PASS,
987*4882a593Smuzhiyun "AUTO_READ_MODE");
988*4882a593Smuzhiyun if (status)
989*4882a593Smuzhiyun goto fail;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun success:
992*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "***** Firmware Loading successful *****\n");
993*4882a593Smuzhiyun release_firmware(fw_entry);
994*4882a593Smuzhiyun return 0;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun fail:
997*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "##### Firmware loading failed #####\n");
998*4882a593Smuzhiyun release_firmware(fw_entry);
999*4882a593Smuzhiyun return status;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
rsi_load_9116_firmware(struct rsi_hw * adapter)1002*4882a593Smuzhiyun static int rsi_load_9116_firmware(struct rsi_hw *adapter)
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun struct rsi_common *common = adapter->priv;
1005*4882a593Smuzhiyun struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
1006*4882a593Smuzhiyun const struct firmware *fw_entry;
1007*4882a593Smuzhiyun struct ta_metadata *metadata_p;
1008*4882a593Smuzhiyun u8 *ta_firmware, *fw_p;
1009*4882a593Smuzhiyun struct bootload_ds bootload_ds;
1010*4882a593Smuzhiyun u32 instructions_sz, base_address;
1011*4882a593Smuzhiyun u16 block_size = adapter->block_size;
1012*4882a593Smuzhiyun u32 dest, len;
1013*4882a593Smuzhiyun int status, cnt;
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "***** Load 9116 TA Instructions *****\n");
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
1018*4882a593Smuzhiyun status = bl_cmd(adapter, POLLING_MODE, CMD_PASS,
1019*4882a593Smuzhiyun "POLLING_MODE");
1020*4882a593Smuzhiyun if (status < 0)
1021*4882a593Smuzhiyun return status;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun status = hif_ops->master_reg_write(adapter, MEM_ACCESS_CTRL_FROM_HOST,
1025*4882a593Smuzhiyun RAM_384K_ACCESS_FROM_TA,
1026*4882a593Smuzhiyun RSI_9116_REG_SIZE);
1027*4882a593Smuzhiyun if (status < 0) {
1028*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Unable to access full RAM memory\n",
1029*4882a593Smuzhiyun __func__);
1030*4882a593Smuzhiyun return status;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun metadata_p = &metadata[adapter->priv->coex_mode];
1034*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "%s: loading file %s\n", __func__, metadata_p->name);
1035*4882a593Smuzhiyun status = request_firmware(&fw_entry, metadata_p->name, adapter->device);
1036*4882a593Smuzhiyun if (status < 0) {
1037*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Failed to open file %s\n",
1038*4882a593Smuzhiyun __func__, metadata_p->name);
1039*4882a593Smuzhiyun return status;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun ta_firmware = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
1043*4882a593Smuzhiyun if (!ta_firmware) {
1044*4882a593Smuzhiyun status = -ENOMEM;
1045*4882a593Smuzhiyun goto fail_release_fw;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun fw_p = ta_firmware;
1048*4882a593Smuzhiyun instructions_sz = fw_entry->size;
1049*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "FW Length = %d bytes\n", instructions_sz);
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun common->lmac_ver.major = ta_firmware[LMAC_VER_OFFSET_9116];
1052*4882a593Smuzhiyun common->lmac_ver.minor = ta_firmware[LMAC_VER_OFFSET_9116 + 1];
1053*4882a593Smuzhiyun common->lmac_ver.release_num = ta_firmware[LMAC_VER_OFFSET_9116 + 2];
1054*4882a593Smuzhiyun common->lmac_ver.patch_num = ta_firmware[LMAC_VER_OFFSET_9116 + 3];
1055*4882a593Smuzhiyun common->lmac_ver.ver.info.fw_ver[0] =
1056*4882a593Smuzhiyun ta_firmware[LMAC_VER_OFFSET_9116 + 4];
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun if (instructions_sz % FW_ALIGN_SIZE)
1059*4882a593Smuzhiyun instructions_sz +=
1060*4882a593Smuzhiyun (FW_ALIGN_SIZE - (instructions_sz % FW_ALIGN_SIZE));
1061*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "instructions_sz : %d\n", instructions_sz);
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun if (*(u16 *)fw_p == RSI_9116_FW_MAGIC_WORD) {
1064*4882a593Smuzhiyun memcpy(&bootload_ds, fw_p, sizeof(struct bootload_ds));
1065*4882a593Smuzhiyun fw_p += le16_to_cpu(bootload_ds.offset);
1066*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "FW start = %x\n", *(u32 *)fw_p);
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun cnt = 0;
1069*4882a593Smuzhiyun do {
1070*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "%s: Loading chunk %d\n",
1071*4882a593Smuzhiyun __func__, cnt);
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun dest = le32_to_cpu(bootload_ds.bl_entry[cnt].dst_addr);
1074*4882a593Smuzhiyun len = le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
1075*4882a593Smuzhiyun RSI_BL_CTRL_LEN_MASK;
1076*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "length %d destination %x\n",
1077*4882a593Smuzhiyun len, dest);
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun status = hif_ops->load_data_master_write(adapter, dest,
1080*4882a593Smuzhiyun len,
1081*4882a593Smuzhiyun block_size,
1082*4882a593Smuzhiyun fw_p);
1083*4882a593Smuzhiyun if (status < 0) {
1084*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
1085*4882a593Smuzhiyun "Failed to load chunk %d\n", cnt);
1086*4882a593Smuzhiyun break;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun fw_p += len;
1089*4882a593Smuzhiyun if (le32_to_cpu(bootload_ds.bl_entry[cnt].control) &
1090*4882a593Smuzhiyun RSI_BL_CTRL_LAST_ENTRY)
1091*4882a593Smuzhiyun break;
1092*4882a593Smuzhiyun cnt++;
1093*4882a593Smuzhiyun } while (1);
1094*4882a593Smuzhiyun } else {
1095*4882a593Smuzhiyun base_address = metadata_p->address;
1096*4882a593Smuzhiyun status = hif_ops->load_data_master_write(adapter,
1097*4882a593Smuzhiyun base_address,
1098*4882a593Smuzhiyun instructions_sz,
1099*4882a593Smuzhiyun block_size,
1100*4882a593Smuzhiyun ta_firmware);
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun if (status) {
1103*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
1104*4882a593Smuzhiyun "%s: Unable to load %s blk\n",
1105*4882a593Smuzhiyun __func__, metadata_p->name);
1106*4882a593Smuzhiyun goto fail_free_fw;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun rsi_dbg(INIT_ZONE, "%s: Successfully loaded %s instructions\n",
1110*4882a593Smuzhiyun __func__, metadata_p->name);
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun if (adapter->rsi_host_intf == RSI_HOST_INTF_SDIO) {
1113*4882a593Smuzhiyun if (hif_ops->ta_reset(adapter))
1114*4882a593Smuzhiyun rsi_dbg(ERR_ZONE, "Unable to put ta in reset\n");
1115*4882a593Smuzhiyun } else {
1116*4882a593Smuzhiyun if (bl_cmd(adapter, JUMP_TO_ZERO_PC,
1117*4882a593Smuzhiyun CMD_PASS, "JUMP_TO_ZERO") < 0)
1118*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Jump to zero command failed\n");
1119*4882a593Smuzhiyun else
1120*4882a593Smuzhiyun rsi_dbg(INFO_ZONE, "Jump to zero command successful\n");
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun fail_free_fw:
1124*4882a593Smuzhiyun kfree(ta_firmware);
1125*4882a593Smuzhiyun fail_release_fw:
1126*4882a593Smuzhiyun release_firmware(fw_entry);
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun return status;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
rsi_hal_device_init(struct rsi_hw * adapter)1131*4882a593Smuzhiyun int rsi_hal_device_init(struct rsi_hw *adapter)
1132*4882a593Smuzhiyun {
1133*4882a593Smuzhiyun struct rsi_common *common = adapter->priv;
1134*4882a593Smuzhiyun int status;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun switch (adapter->device_model) {
1137*4882a593Smuzhiyun case RSI_DEV_9113:
1138*4882a593Smuzhiyun status = rsi_hal_prepare_fwload(adapter);
1139*4882a593Smuzhiyun if (status < 0)
1140*4882a593Smuzhiyun return status;
1141*4882a593Smuzhiyun if (rsi_load_9113_firmware(adapter)) {
1142*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
1143*4882a593Smuzhiyun "%s: Failed to load TA instructions\n",
1144*4882a593Smuzhiyun __func__);
1145*4882a593Smuzhiyun return -EINVAL;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun break;
1148*4882a593Smuzhiyun case RSI_DEV_9116:
1149*4882a593Smuzhiyun status = rsi_hal_prepare_fwload(adapter);
1150*4882a593Smuzhiyun if (status < 0)
1151*4882a593Smuzhiyun return status;
1152*4882a593Smuzhiyun if (rsi_load_9116_firmware(adapter)) {
1153*4882a593Smuzhiyun rsi_dbg(ERR_ZONE,
1154*4882a593Smuzhiyun "%s: Failed to load firmware to 9116 device\n",
1155*4882a593Smuzhiyun __func__);
1156*4882a593Smuzhiyun return -EINVAL;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun break;
1159*4882a593Smuzhiyun default:
1160*4882a593Smuzhiyun return -EINVAL;
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun common->fsm_state = FSM_CARD_NOT_READY;
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun return 0;
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rsi_hal_device_init);
1167*4882a593Smuzhiyun
1168