Commit | Line | Data |
---|---|---|
94a79942 LF |
1 | /****************************************************************************** |
2 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. | |
3 | * | |
4 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
5 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
6 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
7 | * more details. | |
8 | * | |
9 | * You should have received a copy of the GNU General Public License along with | |
10 | * this program; if not, write to the Free Software Foundation, Inc., | |
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in the | |
14 | * file called LICENSE. | |
15 | * | |
16 | * Contact Information: | |
17 | * wlanfae <wlanfae@realtek.com> | |
18 | ******************************************************************************/ | |
19 | ||
94a79942 LF |
20 | #include "rtl_core.h" |
21 | #include "r8192E_hw.h" | |
94a79942 | 22 | #include "r8192E_hwimg.h" |
94a79942 | 23 | #include "r8192E_firmware.h" |
94a79942 | 24 | #include <linux/firmware.h> |
94a79942 | 25 | |
49aab5fd | 26 | void firmware_init_param(struct net_device *dev) |
94a79942 | 27 | { |
e3e37629 | 28 | struct r8192_priv *priv = rtllib_priv(dev); |
5aca114d | 29 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 | 30 | |
11632a0e LF |
31 | pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD( |
32 | MAX_TRANSMIT_BUFFER_SIZE); | |
94a79942 LF |
33 | } |
34 | ||
49aab5fd LF |
35 | static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, |
36 | u32 buffer_len) | |
94a79942 | 37 | { |
e3e37629 | 38 | struct r8192_priv *priv = rtllib_priv(dev); |
94a79942 LF |
39 | bool rt_status = true; |
40 | u16 frag_threshold; | |
41 | u16 frag_length, frag_offset = 0; | |
42 | int i; | |
43 | ||
5aca114d | 44 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
45 | struct sk_buff *skb; |
46 | unsigned char *seg_ptr; | |
3b83db43 | 47 | struct cb_desc *tcb_desc; |
94a79942 LF |
48 | u8 bLastIniPkt; |
49 | ||
50 | firmware_init_param(dev); | |
51 | frag_threshold = pfirmware->cmdpacket_frag_thresold; | |
52 | do { | |
53 | if ((buffer_len - frag_offset) > frag_threshold) { | |
54 | frag_length = frag_threshold ; | |
55 | bLastIniPkt = 0; | |
56 | ||
57 | } else { | |
58 | frag_length = buffer_len - frag_offset; | |
59 | bLastIniPkt = 1; | |
60 | ||
61 | } | |
62 | ||
63 | skb = dev_alloc_skb(frag_length + 4); | |
11632a0e | 64 | memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); |
3b83db43 | 65 | tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); |
94a79942 LF |
66 | tcb_desc->queue_index = TXCMD_QUEUE; |
67 | tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; | |
68 | tcb_desc->bLastIniPkt = bLastIniPkt; | |
69 | ||
70 | seg_ptr = skb->data; | |
11632a0e LF |
71 | for (i = 0; i < frag_length; i += 4) { |
72 | *seg_ptr++ = ((i+0) < frag_length) ? | |
73 | code_virtual_address[i+3] : 0; | |
74 | *seg_ptr++ = ((i+1) < frag_length) ? | |
75 | code_virtual_address[i+2] : 0; | |
76 | *seg_ptr++ = ((i+2) < frag_length) ? | |
77 | code_virtual_address[i+1] : 0; | |
78 | *seg_ptr++ = ((i+3) < frag_length) ? | |
79 | code_virtual_address[i+0] : 0; | |
94a79942 | 80 | } |
11632a0e | 81 | tcb_desc->txbuf_size = (u16)i; |
94a79942 LF |
82 | skb_put(skb, i); |
83 | ||
11632a0e LF |
84 | if (!priv->rtllib->check_nic_enough_desc(dev, tcb_desc->queue_index) || |
85 | (!skb_queue_empty(&priv->rtllib->skb_waitQ[tcb_desc->queue_index])) || | |
86 | (priv->rtllib->queue_stop)) { | |
87 | RT_TRACE(COMP_FIRMWARE, "===================> tx " | |
88 | "full!\n"); | |
89 | skb_queue_tail(&priv->rtllib->skb_waitQ | |
90 | [tcb_desc->queue_index], skb); | |
94a79942 | 91 | } else { |
11632a0e | 92 | priv->rtllib->softmac_hard_start_xmit(skb, dev); |
94a79942 LF |
93 | } |
94 | ||
95 | code_virtual_address += frag_length; | |
96 | frag_offset += frag_length; | |
97 | ||
11632a0e | 98 | } while (frag_offset < buffer_len); |
94a79942 LF |
99 | |
100 | write_nic_byte(dev, TPPoll, TPPoll_CQ); | |
101 | ||
102 | return rt_status; | |
103 | } | |
104 | ||
49aab5fd | 105 | static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) |
94a79942 LF |
106 | { |
107 | bool rt_status = true; | |
108 | u32 CPU_status = 0; | |
109 | unsigned long timeout; | |
110 | ||
111 | timeout = jiffies + MSECS(200); | |
112 | while (time_before(jiffies, timeout)) { | |
113 | CPU_status = read_nic_dword(dev, CPU_GEN); | |
114 | if (CPU_status & CPU_GEN_PUT_CODE_OK) | |
115 | break; | |
11632a0e | 116 | mdelay(2); |
94a79942 LF |
117 | } |
118 | ||
119 | if (!(CPU_status&CPU_GEN_PUT_CODE_OK)) { | |
120 | RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); | |
121 | goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; | |
122 | } else { | |
123 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); | |
124 | } | |
125 | ||
126 | CPU_status = read_nic_dword(dev, CPU_GEN); | |
11632a0e LF |
127 | write_nic_byte(dev, CPU_GEN, |
128 | (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); | |
94a79942 LF |
129 | mdelay(1); |
130 | ||
131 | timeout = jiffies + MSECS(200); | |
132 | while (time_before(jiffies, timeout)) { | |
133 | CPU_status = read_nic_dword(dev, CPU_GEN); | |
134 | if (CPU_status&CPU_GEN_BOOT_RDY) | |
135 | break; | |
11632a0e | 136 | mdelay(2); |
94a79942 LF |
137 | } |
138 | ||
11632a0e | 139 | if (!(CPU_status&CPU_GEN_BOOT_RDY)) |
94a79942 | 140 | goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; |
11632a0e | 141 | else |
94a79942 | 142 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); |
94a79942 LF |
143 | |
144 | return rt_status; | |
145 | ||
146 | CPUCheckMainCodeOKAndTurnOnCPU_Fail: | |
147 | RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); | |
148 | rt_status = false; | |
149 | return rt_status; | |
150 | } | |
151 | ||
49aab5fd | 152 | static bool CPUcheck_firmware_ready(struct net_device *dev) |
94a79942 LF |
153 | { |
154 | ||
155 | bool rt_status = true; | |
156 | u32 CPU_status = 0; | |
157 | unsigned long timeout; | |
158 | ||
159 | timeout = jiffies + MSECS(20); | |
160 | while (time_before(jiffies, timeout)) { | |
161 | CPU_status = read_nic_dword(dev, CPU_GEN); | |
162 | if (CPU_status&CPU_GEN_FIRM_RDY) | |
163 | break; | |
11632a0e | 164 | mdelay(2); |
94a79942 LF |
165 | } |
166 | ||
167 | if (!(CPU_status&CPU_GEN_FIRM_RDY)) | |
168 | goto CPUCheckFirmwareReady_Fail; | |
169 | else | |
170 | RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); | |
171 | ||
172 | return rt_status; | |
173 | ||
174 | CPUCheckFirmwareReady_Fail: | |
175 | RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); | |
176 | rt_status = false; | |
177 | return rt_status; | |
178 | ||
179 | } | |
180 | ||
11632a0e LF |
181 | static bool firmware_check_ready(struct net_device *dev, |
182 | u8 load_fw_status) | |
94a79942 | 183 | { |
e3e37629 | 184 | struct r8192_priv *priv = rtllib_priv(dev); |
5aca114d | 185 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
186 | bool rt_status = true; |
187 | ||
188 | switch (load_fw_status) { | |
189 | case FW_INIT_STEP0_BOOT: | |
190 | pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; | |
94a79942 LF |
191 | break; |
192 | ||
193 | case FW_INIT_STEP1_MAIN: | |
194 | pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; | |
195 | ||
196 | rt_status = CPUcheck_maincodeok_turnonCPU(dev); | |
11632a0e | 197 | if (rt_status) |
94a79942 | 198 | pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; |
11632a0e LF |
199 | else |
200 | RT_TRACE(COMP_FIRMWARE, "CPUcheck_maincodeok_turnon" | |
201 | "CPU fail!\n"); | |
94a79942 LF |
202 | |
203 | break; | |
204 | ||
205 | case FW_INIT_STEP2_DATA: | |
206 | pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; | |
207 | mdelay(1); | |
208 | ||
209 | rt_status = CPUcheck_firmware_ready(dev); | |
11632a0e | 210 | if (rt_status) |
94a79942 | 211 | pfirmware->firmware_status = FW_STATUS_5_READY; |
11632a0e LF |
212 | else |
213 | RT_TRACE(COMP_FIRMWARE, "CPUcheck_firmware_ready fail" | |
214 | "(%d)!\n", rt_status); | |
94a79942 LF |
215 | |
216 | break; | |
217 | default: | |
218 | rt_status = false; | |
73e29189 | 219 | RT_TRACE(COMP_FIRMWARE, "Unknown firmware status"); |
94a79942 LF |
220 | break; |
221 | } | |
222 | ||
223 | return rt_status; | |
224 | } | |
225 | ||
226 | bool init_firmware(struct net_device *dev) | |
227 | { | |
e3e37629 | 228 | struct r8192_priv *priv = rtllib_priv(dev); |
94a79942 LF |
229 | bool rt_status = true; |
230 | ||
94a79942 LF |
231 | u8 *firmware_img_buf[3] = { &Rtl8192PciEFwBootArray[0], |
232 | &Rtl8192PciEFwMainArray[0], | |
233 | &Rtl8192PciEFwDataArray[0]}; | |
234 | ||
235 | u32 firmware_img_len[3] = { sizeof(Rtl8192PciEFwBootArray), | |
236 | sizeof(Rtl8192PciEFwMainArray), | |
237 | sizeof(Rtl8192PciEFwDataArray)}; | |
94a79942 LF |
238 | u32 file_length = 0; |
239 | u8 *mapped_file = NULL; | |
240 | u8 init_step = 0; | |
6bf04003 | 241 | enum opt_rst_type rst_opt = OPT_SYSTEM_RESET; |
cec07695 | 242 | enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT; |
94a79942 | 243 | |
5aca114d | 244 | struct rt_firmware *pfirmware = priv->pFirmware; |
94a79942 LF |
245 | |
246 | RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); | |
247 | ||
11632a0e | 248 | if (pfirmware->firmware_status == FW_STATUS_0_INIT) { |
94a79942 LF |
249 | rst_opt = OPT_SYSTEM_RESET; |
250 | starting_state = FW_INIT_STEP0_BOOT; | |
251 | ||
11632a0e | 252 | } else if (pfirmware->firmware_status == FW_STATUS_5_READY) { |
94a79942 LF |
253 | rst_opt = OPT_FIRMWARE_RESET; |
254 | starting_state = FW_INIT_STEP2_DATA; | |
11632a0e LF |
255 | } else { |
256 | RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined" | |
257 | " firmware state\n"); | |
94a79942 LF |
258 | } |
259 | ||
94a79942 | 260 | priv->firmware_source = FW_SOURCE_IMG_FILE; |
11632a0e LF |
261 | for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; |
262 | init_step++) { | |
94a79942 LF |
263 | if (rst_opt == OPT_SYSTEM_RESET) { |
264 | switch (priv->firmware_source) { | |
265 | case FW_SOURCE_IMG_FILE: | |
266 | { | |
94a79942 | 267 | if (pfirmware->firmware_buf_size[init_step] == 0) { |
7f34f412 TG |
268 | const char *fw_name[3] = { |
269 | RTL8192E_BOOT_IMG_FW, | |
270 | RTL8192E_MAIN_IMG_FW, | |
271 | RTL8192E_DATA_IMG_FW | |
272 | }; | |
94a79942 LF |
273 | const struct firmware *fw_entry; |
274 | int rc; | |
11632a0e LF |
275 | rc = request_firmware(&fw_entry, |
276 | fw_name[init_step], &priv->pdev->dev); | |
277 | if (rc < 0) { | |
278 | RT_TRACE(COMP_FIRMWARE, "request firm" | |
279 | "ware fail!\n"); | |
94a79942 LF |
280 | goto download_firmware_fail; |
281 | } | |
11632a0e LF |
282 | if (fw_entry->size > |
283 | sizeof(pfirmware->firmware_buf[init_step])) { | |
284 | RT_TRACE(COMP_FIRMWARE, "img file size " | |
285 | "exceed the container struct " | |
286 | "buffer fail!\n"); | |
94a79942 LF |
287 | goto download_firmware_fail; |
288 | } | |
289 | ||
290 | if (init_step != FW_INIT_STEP1_MAIN) { | |
11632a0e LF |
291 | memcpy(pfirmware->firmware_buf[init_step], |
292 | fw_entry->data, fw_entry->size); | |
293 | pfirmware->firmware_buf_size[init_step] = | |
294 | fw_entry->size; | |
94a79942 LF |
295 | |
296 | } else { | |
11632a0e LF |
297 | memset(pfirmware->firmware_buf[init_step], |
298 | 0, 128); | |
299 | memcpy(&pfirmware->firmware_buf[init_step][128], | |
300 | fw_entry->data, fw_entry->size); | |
301 | pfirmware->firmware_buf_size[init_step] = | |
302 | fw_entry->size + 128; | |
94a79942 LF |
303 | } |
304 | ||
11632a0e | 305 | if (rst_opt == OPT_SYSTEM_RESET) |
94a79942 | 306 | release_firmware(fw_entry); |
94a79942 LF |
307 | } |
308 | mapped_file = pfirmware->firmware_buf[init_step]; | |
309 | file_length = pfirmware->firmware_buf_size[init_step]; | |
94a79942 LF |
310 | break; |
311 | } | |
312 | case FW_SOURCE_HEADER_FILE: | |
313 | mapped_file = firmware_img_buf[init_step]; | |
314 | file_length = firmware_img_len[init_step]; | |
315 | if (init_step == FW_INIT_STEP2_DATA) { | |
316 | memcpy(pfirmware->firmware_buf[init_step], mapped_file, file_length); | |
317 | pfirmware->firmware_buf_size[init_step] = file_length; | |
318 | } | |
319 | break; | |
320 | ||
321 | default: | |
322 | break; | |
323 | } | |
324 | ||
325 | ||
326 | } else if (rst_opt == OPT_FIRMWARE_RESET) { | |
327 | mapped_file = pfirmware->firmware_buf[init_step]; | |
328 | file_length = pfirmware->firmware_buf_size[init_step]; | |
329 | } | |
330 | ||
11632a0e | 331 | rt_status = fw_download_code(dev, mapped_file, file_length); |
94a79942 LF |
332 | if (rt_status != true) { |
333 | goto download_firmware_fail; | |
334 | } | |
335 | ||
336 | if (!firmware_check_ready(dev, init_step)) { | |
337 | goto download_firmware_fail; | |
338 | } | |
339 | } | |
340 | ||
341 | RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); | |
342 | return rt_status; | |
343 | ||
344 | download_firmware_fail: | |
345 | RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__); | |
346 | rt_status = false; | |
347 | return rt_status; | |
348 | ||
349 | } |