r819xU_firmware.c revision 9b0131cb24182ef6cc478a89fc56fc6e004651e7
1/************************************************************************************************** 2 * Procedure: Init boot code/firmware code/data session 3 * 4 * Description: This routine will initialize firmware. If any error occurs during the initialization 5 * process, the routine shall terminate immediately and return fail. 6 * NIC driver should call NdisOpenFile only from MiniportInitialize. 7 * 8 * Arguments: The pointer of the adapter 9 10 * Returns: 11 * NDIS_STATUS_FAILURE - the following initialization process should be terminated 12 * NDIS_STATUS_SUCCESS - if firmware initialization process success 13**************************************************************************************************/ 14 15#include "r8192U.h" 16#include "r8192U_hw.h" 17#include "r819xU_firmware_img.h" 18#include "r819xU_firmware.h" 19#include <linux/firmware.h> 20void firmware_init_param(struct net_device *dev) 21{ 22 struct r8192_priv *priv = ieee80211_priv(dev); 23 rt_firmware *pfirmware = priv->pFirmware; 24 25 pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE); 26} 27 28/* 29 * segment the img and use the ptr and length to remember info on each segment 30 * 31 */ 32bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len) 33{ 34 struct r8192_priv *priv = ieee80211_priv(dev); 35 bool rt_status = true; 36 u16 frag_threshold; 37 u16 frag_length, frag_offset = 0; 38 //u16 total_size; 39 int i; 40 41 rt_firmware *pfirmware = priv->pFirmware; 42 struct sk_buff *skb; 43 unsigned char *seg_ptr; 44 cb_desc *tcb_desc; 45 u8 bLastIniPkt; 46 47 firmware_init_param(dev); 48 //Fragmentation might be required 49 frag_threshold = pfirmware->cmdpacket_frag_thresold; 50 do { 51 if((buffer_len - frag_offset) > frag_threshold) { 52 frag_length = frag_threshold ; 53 bLastIniPkt = 0; 54 55 } else { 56 frag_length = buffer_len - frag_offset; 57 bLastIniPkt = 1; 58 59 } 60 61 /* Allocate skb buffer to contain firmware info and tx descriptor info 62 * add 4 to avoid packet appending overflow. 63 * */ 64 #ifdef RTL8192U 65 skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); 66 #else 67 skb = dev_alloc_skb(frag_length + 4); 68 #endif 69 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); 70 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); 71 tcb_desc->queue_index = TXCMD_QUEUE; 72 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; 73 tcb_desc->bLastIniPkt = bLastIniPkt; 74 75 #ifdef RTL8192U 76 skb_reserve(skb, USB_HWDESC_HEADER_LEN); 77 #endif 78 seg_ptr = skb->data; 79 /* 80 * Transform from little endian to big endian 81 * and pending zero 82 */ 83 for(i=0 ; i < frag_length; i+=4) { 84 *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0; 85 *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0; 86 *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0; 87 *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0; 88 } 89 tcb_desc->txbuf_size= (u16)i; 90 skb_put(skb, i); 91 92 if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| 93 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ 94 (priv->ieee80211->queue_stop) ) { 95 RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); 96 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); 97 } else { 98 priv->ieee80211->softmac_hard_start_xmit(skb,dev); 99 } 100 101 code_virtual_address += frag_length; 102 frag_offset += frag_length; 103 104 }while(frag_offset < buffer_len); 105 106 return rt_status; 107 108} 109 110bool 111fwSendNullPacket( 112 struct net_device *dev, 113 u32 Length 114) 115{ 116 bool rtStatus = true; 117 struct r8192_priv *priv = ieee80211_priv(dev); 118 struct sk_buff *skb; 119 cb_desc *tcb_desc; 120 unsigned char *ptr_buf; 121 bool bLastInitPacket = false; 122 123 //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); 124 125 //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) 126 skb = dev_alloc_skb(Length+ 4); 127 memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); 128 tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); 129 tcb_desc->queue_index = TXCMD_QUEUE; 130 tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; 131 tcb_desc->bLastIniPkt = bLastInitPacket; 132 ptr_buf = skb_put(skb, Length); 133 memset(ptr_buf,0,Length); 134 tcb_desc->txbuf_size= (u16)Length; 135 136 if(!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)|| 137 (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\ 138 (priv->ieee80211->queue_stop) ) { 139 RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n"); 140 skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); 141 } else { 142 priv->ieee80211->softmac_hard_start_xmit(skb,dev); 143 } 144 145 //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); 146 return rtStatus; 147} 148 149 150//----------------------------------------------------------------------------- 151// Procedure: Check whether main code is download OK. If OK, turn on CPU 152// 153// Description: CPU register locates in different page against general register. 154// Switch to CPU register in the begin and switch back before return 155// 156// 157// Arguments: The pointer of the adapter 158// 159// Returns: 160// NDIS_STATUS_FAILURE - the following initialization process should be terminated 161// NDIS_STATUS_SUCCESS - if firmware initialization process success 162//----------------------------------------------------------------------------- 163bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) 164{ 165 bool rt_status = true; 166 int check_putcodeOK_time = 200000, check_bootOk_time = 200000; 167 u32 CPU_status = 0; 168 169 /* Check whether put code OK */ 170 do { 171 CPU_status = read_nic_dword(dev, CPU_GEN); 172 173 if(CPU_status&CPU_GEN_PUT_CODE_OK) 174 break; 175 176 }while(check_putcodeOK_time--); 177 178 if(!(CPU_status&CPU_GEN_PUT_CODE_OK)) { 179 RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); 180 goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; 181 } else { 182 RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); 183 } 184 185 /* Turn On CPU */ 186 CPU_status = read_nic_dword(dev, CPU_GEN); 187 write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); 188 mdelay(1000); 189 190 /* Check whether CPU boot OK */ 191 do { 192 CPU_status = read_nic_dword(dev, CPU_GEN); 193 194 if(CPU_status&CPU_GEN_BOOT_RDY) 195 break; 196 }while(check_bootOk_time--); 197 198 if(!(CPU_status&CPU_GEN_BOOT_RDY)) { 199 goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; 200 } else { 201 RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); 202 } 203 204 return rt_status; 205 206CPUCheckMainCodeOKAndTurnOnCPU_Fail: 207 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 208 rt_status = FALSE; 209 return rt_status; 210} 211 212bool CPUcheck_firmware_ready(struct net_device *dev) 213{ 214 215 bool rt_status = true; 216 int check_time = 200000; 217 u32 CPU_status = 0; 218 219 /* Check Firmware Ready */ 220 do { 221 CPU_status = read_nic_dword(dev, CPU_GEN); 222 223 if(CPU_status&CPU_GEN_FIRM_RDY) 224 break; 225 226 }while(check_time--); 227 228 if(!(CPU_status&CPU_GEN_FIRM_RDY)) 229 goto CPUCheckFirmwareReady_Fail; 230 else 231 RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); 232 233 return rt_status; 234 235CPUCheckFirmwareReady_Fail: 236 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 237 rt_status = false; 238 return rt_status; 239 240} 241 242bool init_firmware(struct net_device *dev) 243{ 244 struct r8192_priv *priv = ieee80211_priv(dev); 245 bool rt_status = TRUE; 246 247 u8 *firmware_img_buf[3] = { &rtl8190_fwboot_array[0], 248 &rtl8190_fwmain_array[0], 249 &rtl8190_fwdata_array[0]}; 250 251 u32 firmware_img_len[3] = { sizeof(rtl8190_fwboot_array), 252 sizeof(rtl8190_fwmain_array), 253 sizeof(rtl8190_fwdata_array)}; 254 u32 file_length = 0; 255 u8 *mapped_file = NULL; 256 u32 init_step = 0; 257 opt_rst_type_e rst_opt = OPT_SYSTEM_RESET; 258 firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT; 259 260 rt_firmware *pfirmware = priv->pFirmware; 261 const struct firmware *fw_entry; 262 const char *fw_name[3] = { "RTL8192U/boot.img", 263 "RTL8192U/main.img", 264 "RTL8192U/data.img"}; 265 int rc; 266 267 RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); 268 269 if (pfirmware->firmware_status == FW_STATUS_0_INIT ) { 270 /* it is called by reset */ 271 rst_opt = OPT_SYSTEM_RESET; 272 starting_state = FW_INIT_STEP0_BOOT; 273 // TODO: system reset 274 275 }else if(pfirmware->firmware_status == FW_STATUS_5_READY) { 276 /* it is called by Initialize */ 277 rst_opt = OPT_FIRMWARE_RESET; 278 starting_state = FW_INIT_STEP2_DATA; 279 }else { 280 RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n"); 281 } 282 283 /* 284 * Download boot, main, and data image for System reset. 285 * Download data image for firmware reseta 286 */ 287 priv->firmware_source = FW_SOURCE_IMG_FILE; 288 for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { 289 /* 290 * Open Image file, and map file to contineous memory if open file success. 291 * or read image file from array. Default load from IMG file 292 */ 293 if(rst_opt == OPT_SYSTEM_RESET) { 294 switch(priv->firmware_source) { 295 case FW_SOURCE_IMG_FILE: 296 rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev); 297 if(rc < 0 ) { 298 RT_TRACE(COMP_ERR, "request firmware fail!\n"); 299 goto download_firmware_fail; 300 } 301 302 if(fw_entry->size > sizeof(pfirmware->firmware_buf)) { 303 RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); 304 goto download_firmware_fail; 305 } 306 307 if(init_step != FW_INIT_STEP1_MAIN) { 308 memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); 309 mapped_file = pfirmware->firmware_buf; 310 file_length = fw_entry->size; 311 } else { 312 #ifdef RTL8190P 313 memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); 314 mapped_file = pfirmware->firmware_buf; 315 file_length = fw_entry->size; 316 #else 317 memset(pfirmware->firmware_buf,0,128); 318 memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size); 319 mapped_file = pfirmware->firmware_buf; 320 file_length = fw_entry->size + 128; 321 #endif 322 } 323 pfirmware->firmware_buf_size = file_length; 324 break; 325 326 case FW_SOURCE_HEADER_FILE: 327 mapped_file = firmware_img_buf[init_step]; 328 file_length = firmware_img_len[init_step]; 329 if(init_step == FW_INIT_STEP2_DATA) { 330 memcpy(pfirmware->firmware_buf, mapped_file, file_length); 331 pfirmware->firmware_buf_size = file_length; 332 } 333 break; 334 335 default: 336 break; 337 } 338 339 340 }else if(rst_opt == OPT_FIRMWARE_RESET ) { 341 /* we only need to download data.img here */ 342 mapped_file = pfirmware->firmware_buf; 343 file_length = pfirmware->firmware_buf_size; 344 } 345 346 /* Download image file */ 347 /* The firmware download process is just as following, 348 * 1. that is each packet will be segmented and inserted to the wait queue. 349 * 2. each packet segment will be put in the skb_buff packet. 350 * 3. each skb_buff packet data content will already include the firmware info 351 * and Tx descriptor info 352 * */ 353 rt_status = fw_download_code(dev,mapped_file,file_length); 354 if(rst_opt == OPT_SYSTEM_RESET) { 355 release_firmware(fw_entry); 356 } 357 358 if(rt_status != TRUE) { 359 goto download_firmware_fail; 360 } 361 362 switch(init_step) { 363 case FW_INIT_STEP0_BOOT: 364 /* Download boot 365 * initialize command descriptor. 366 * will set polling bit when firmware code is also configured 367 */ 368 pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; 369#ifdef RTL8190P 370 // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet 371 rt_status = fwSendNullPacket(dev, RTL8190_CPU_START_OFFSET); 372 if(rt_status != true) 373 { 374 RT_TRACE(COMP_INIT, "fwSendNullPacket() fail ! \n"); 375 goto download_firmware_fail; 376 } 377#endif 378 //mdelay(1000); 379 /* 380 * To initialize IMEM, CPU move code from 0x80000080, 381 * hence, we send 0x80 byte packet 382 */ 383 break; 384 385 case FW_INIT_STEP1_MAIN: 386 /* Download firmware code. Wait until Boot Ready and Turn on CPU */ 387 pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; 388 389 /* Check Put Code OK and Turn On CPU */ 390 rt_status = CPUcheck_maincodeok_turnonCPU(dev); 391 if(rt_status != TRUE) { 392 RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n"); 393 goto download_firmware_fail; 394 } 395 396 pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; 397 break; 398 399 case FW_INIT_STEP2_DATA: 400 /* download initial data code */ 401 pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; 402 mdelay(1); 403 404 rt_status = CPUcheck_firmware_ready(dev); 405 if(rt_status != TRUE) { 406 RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); 407 goto download_firmware_fail; 408 } 409 410 /* wait until data code is initialized ready.*/ 411 pfirmware->firmware_status = FW_STATUS_5_READY; 412 break; 413 } 414 } 415 416 RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); 417 //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n")); 418 419 return rt_status; 420 421download_firmware_fail: 422 RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); 423 rt_status = FALSE; 424 return rt_status; 425 426} 427 428 429 430 431 432 433 434 435