1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2009-2012 Realtek Corporation.*/
3
4 #include "../wifi.h"
5 #include "../pci.h"
6 #include "../base.h"
7 #include "../efuse.h"
8 #include "../rtl8192d/reg.h"
9 #include "../rtl8192d/def.h"
10 #include "../rtl8192d/fw_common.h"
11 #include "fw.h"
12 #include "sw.h"
13
rtl92d_download_fw(struct ieee80211_hw * hw)14 int rtl92d_download_fw(struct ieee80211_hw *hw)
15 {
16 struct rtl_priv *rtlpriv = rtl_priv(hw);
17 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
18 u8 *pfwheader;
19 u8 *pfwdata;
20 u32 fwsize;
21 int err;
22 enum version_8192d version = rtlhal->version;
23 u8 value;
24 u32 count;
25 bool fw_downloaded = false, fwdl_in_process = false;
26 unsigned long flags;
27
28 if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
29 return 1;
30 fwsize = rtlhal->fwsize;
31 pfwheader = rtlhal->pfirmware;
32 pfwdata = rtlhal->pfirmware;
33 rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
34 rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
35 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
36 "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
37 rtlhal->fw_version, rtlhal->fw_subversion,
38 GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
39 if (IS_FW_HEADER_EXIST(pfwheader)) {
40 rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
41 "Shift 32 bytes for FW header!!\n");
42 pfwdata = pfwdata + 32;
43 fwsize = fwsize - 32;
44 }
45
46 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
47 fw_downloaded = rtl92d_is_fw_downloaded(rtlpriv);
48 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
49 fwdl_in_process = true;
50 else
51 fwdl_in_process = false;
52 if (fw_downloaded) {
53 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
54 goto exit;
55 } else if (fwdl_in_process) {
56 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
57 for (count = 0; count < 5000; count++) {
58 udelay(500);
59 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
60 fw_downloaded = rtl92d_is_fw_downloaded(rtlpriv);
61 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
62 fwdl_in_process = true;
63 else
64 fwdl_in_process = false;
65 spin_unlock_irqrestore(&globalmutex_for_fwdownload,
66 flags);
67 if (fw_downloaded)
68 goto exit;
69 else if (!fwdl_in_process)
70 break;
71 else
72 rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
73 "Wait for another mac download fw\n");
74 }
75 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
76 value = rtl_read_byte(rtlpriv, 0x1f);
77 value |= BIT(5);
78 rtl_write_byte(rtlpriv, 0x1f, value);
79 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
80 } else {
81 value = rtl_read_byte(rtlpriv, 0x1f);
82 value |= BIT(5);
83 rtl_write_byte(rtlpriv, 0x1f, value);
84 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
85 }
86
87 /* If 8051 is running in RAM code, driver should
88 * inform Fw to reset by itself, or it will cause
89 * download Fw fail.*/
90 /* 8051 RAM code */
91 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
92 rtl92d_firmware_selfreset(hw);
93 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
94 }
95 rtl92d_enable_fw_download(hw, true);
96 rtl92d_write_fw(hw, version, pfwdata, fwsize);
97 rtl92d_enable_fw_download(hw, false);
98 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
99 err = rtl92d_fw_free_to_go(hw);
100 /* download fw over,clear 0x1f[5] */
101 value = rtl_read_byte(rtlpriv, 0x1f);
102 value &= (~BIT(5));
103 rtl_write_byte(rtlpriv, 0x1f, value);
104 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
105 if (err)
106 pr_err("fw is not ready to run!\n");
107 exit:
108 err = rtl92d_fw_init(hw);
109 return err;
110 }
111
_rtl92d_cmd_send_packet(struct ieee80211_hw * hw,struct sk_buff * skb)112 static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
113 struct sk_buff *skb)
114 {
115 struct rtl_priv *rtlpriv = rtl_priv(hw);
116 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
117 struct rtl8192_tx_ring *ring;
118 struct rtl_tx_desc *pdesc;
119 u8 idx = 0;
120 unsigned long flags;
121 struct sk_buff *pskb;
122
123 ring = &rtlpci->tx_ring[BEACON_QUEUE];
124 pskb = __skb_dequeue(&ring->queue);
125 kfree_skb(pskb);
126 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
127 pdesc = &ring->desc[idx];
128 /* discard output from call below */
129 rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN);
130 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, skb);
131 __skb_queue_tail(&ring->queue, skb);
132 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
133 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
134 return true;
135 }
136
137 #define BEACON_PG 0 /*->1 */
138 #define PSPOLL_PG 2
139 #define NULL_PG 3
140 #define PROBERSP_PG 4 /*->5 */
141 #define TOTAL_RESERVED_PKT_LEN 768
142
143 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
144 /* page 0 beacon */
145 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
146 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
147 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
150 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
151 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
152 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
153 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
154 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
155 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
159 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161
162 /* page 1 beacon */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179
180 /* page 2 ps-poll */
181 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
182 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
195 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197
198 /* page 3 null */
199 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
200 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
201 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
202 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
212 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
213 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215
216 /* page 4 probe_resp */
217 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
218 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
219 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
220 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
221 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
222 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
223 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
224 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
225 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
226 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
227 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
231 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233
234 /* page 5 probe_resp */
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 };
252
rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool dl_finished)253 void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
254 {
255 struct rtl_priv *rtlpriv = rtl_priv(hw);
256 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
257 struct sk_buff *skb = NULL;
258 u32 totalpacketlen;
259 bool rtstatus;
260 u8 u1rsvdpageloc[3] = { PROBERSP_PG, PSPOLL_PG, NULL_PG };
261 bool dlok = false;
262 u8 *beacon;
263 u8 *p_pspoll;
264 u8 *nullfunc;
265 u8 *p_probersp;
266 /*---------------------------------------------------------
267 (1) beacon
268 ---------------------------------------------------------*/
269 beacon = &reserved_page_packet[BEACON_PG * 128];
270 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
271 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
272 /*-------------------------------------------------------
273 (2) ps-poll
274 --------------------------------------------------------*/
275 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
276 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
277 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
278 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
279 /*--------------------------------------------------------
280 (3) null data
281 ---------------------------------------------------------*/
282 nullfunc = &reserved_page_packet[NULL_PG * 128];
283 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
284 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
285 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
286 /*---------------------------------------------------------
287 (4) probe response
288 ----------------------------------------------------------*/
289 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
290 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
291 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
292 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
293 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
294 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
295 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
296 &reserved_page_packet[0], totalpacketlen);
297 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
298 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
299 u1rsvdpageloc, 3);
300 skb = dev_alloc_skb(totalpacketlen);
301 if (!skb) {
302 dlok = false;
303 } else {
304 skb_put_data(skb, &reserved_page_packet, totalpacketlen);
305 rtstatus = _rtl92d_cmd_send_packet(hw, skb);
306
307 if (rtstatus)
308 dlok = true;
309 }
310 if (dlok) {
311 rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
312 "Set RSVD page location to Fw\n");
313 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
314 "H2C_RSVDPAGE", u1rsvdpageloc, 3);
315 rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
316 sizeof(u1rsvdpageloc), u1rsvdpageloc);
317 } else
318 rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,
319 "Set RSVD page location to Fw FAIL!!!!!!\n");
320 }
321