1 /**************************************************************************************************
2 * Procedure: Init boot code/firmware code/data session
4 * Description: This routine will intialize 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.
8 * Arguments: The pointer of the adapter
11 * NDIS_STATUS_FAILURE - the following initialization process should be terminated
12 * NDIS_STATUS_SUCCESS - if firmware initialization process success
13 **************************************************************************************************/
14 //#include "ieee80211.h"
16 #include "r8192E_hw.h"
18 #include "r819xP_firmware_img.h"
20 #include "r819xE_firmware_img.h"
22 #include "r819xE_firmware.h"
23 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
24 #include <linux/firmware.h>
27 extern void firmware_init_param(struct net_device
*dev
)
29 struct r8192_priv
*priv
= ieee80211_priv(dev
);
30 rt_firmware
*pfirmware
= priv
->pFirmware
;
32 pfirmware
->cmdpacket_frag_thresold
= GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE
);
36 * segment the img and use the ptr and length to remember info on each segment
39 bool fw_download_code(struct net_device
*dev
, u8
*code_virtual_address
, u32 buffer_len
)
41 struct r8192_priv
*priv
= ieee80211_priv(dev
);
42 bool rt_status
= true;
44 u16 frag_length
, frag_offset
= 0;
48 rt_firmware
*pfirmware
= priv
->pFirmware
;
50 unsigned char *seg_ptr
;
54 firmware_init_param(dev
);
55 //Fragmentation might be required
56 frag_threshold
= pfirmware
->cmdpacket_frag_thresold
;
58 if((buffer_len
- frag_offset
) > frag_threshold
) {
59 frag_length
= frag_threshold
;
63 frag_length
= buffer_len
- frag_offset
;
68 /* Allocate skb buffer to contain firmware info and tx descriptor info
69 * add 4 to avoid packet appending overflow.
71 //skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
72 skb
= dev_alloc_skb(frag_length
+ 4);
73 memcpy((unsigned char *)(skb
->cb
),&dev
,sizeof(dev
));
74 tcb_desc
= (cb_desc
*)(skb
->cb
+ MAX_DEV_ADDR_SIZE
);
75 tcb_desc
->queue_index
= TXCMD_QUEUE
;
76 tcb_desc
->bCmdOrInit
= DESC_PACKET_TYPE_INIT
;
77 tcb_desc
->bLastIniPkt
= bLastIniPkt
;
79 //skb_reserve(skb, USB_HWDESC_HEADER_LEN);
82 * Transform from little endian to big endian
85 for(i
=0 ; i
< frag_length
; i
+=4) {
86 *seg_ptr
++ = ((i
+0)<frag_length
)?code_virtual_address
[i
+3]:0;
87 *seg_ptr
++ = ((i
+1)<frag_length
)?code_virtual_address
[i
+2]:0;
88 *seg_ptr
++ = ((i
+2)<frag_length
)?code_virtual_address
[i
+1]:0;
89 *seg_ptr
++ = ((i
+3)<frag_length
)?code_virtual_address
[i
+0]:0;
91 tcb_desc
->txbuf_size
= (u16
)i
;
93 priv
->ieee80211
->softmac_hard_start_xmit(skb
,dev
);
95 code_virtual_address
+= frag_length
;
96 frag_offset
+= frag_length
;
98 }while(frag_offset
< buffer_len
);
103 cmdsend_downloadcode_fail
:
105 RT_TRACE(COMP_ERR
, "CmdSendDownloadCode fail !!\n");
112 struct net_device
*dev
,
116 bool rtStatus
= true;
117 struct r8192_priv
*priv
= ieee80211_priv(dev
);
120 unsigned char *ptr_buf
;
121 bool bLastInitPacket
= false;
123 //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
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
;
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
);
142 priv
->ieee80211
->softmac_hard_start_xmit(skb
,dev
);
145 //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
149 //-----------------------------------------------------------------------------
150 // Procedure: Check whether main code is download OK. If OK, turn on CPU
152 // Description: CPU register locates in different page against general register.
153 // Switch to CPU register in the begin and switch back before return
156 // Arguments: The pointer of the adapter
159 // NDIS_STATUS_FAILURE - the following initialization process should be terminated
160 // NDIS_STATUS_SUCCESS - if firmware initialization process success
161 //-----------------------------------------------------------------------------
162 bool CPUcheck_maincodeok_turnonCPU(struct net_device
*dev
)
164 bool rt_status
= true;
165 int check_putcodeOK_time
= 200000, check_bootOk_time
= 200000;
168 /* Check whether put code OK */
170 CPU_status
= read_nic_dword(dev
, CPU_GEN
);
172 if(CPU_status
&CPU_GEN_PUT_CODE_OK
)
175 }while(check_putcodeOK_time
--);
177 if(!(CPU_status
&CPU_GEN_PUT_CODE_OK
)) {
178 RT_TRACE(COMP_ERR
, "Download Firmware: Put code fail!\n");
179 goto CPUCheckMainCodeOKAndTurnOnCPU_Fail
;
181 RT_TRACE(COMP_FIRMWARE
, "Download Firmware: Put code ok!\n");
185 CPU_status
= read_nic_dword(dev
, CPU_GEN
);
186 write_nic_byte(dev
, CPU_GEN
, (u8
)((CPU_status
|CPU_GEN_PWR_STB_CPU
)&0xff));
189 /* Check whether CPU boot OK */
191 CPU_status
= read_nic_dword(dev
, CPU_GEN
);
193 if(CPU_status
&CPU_GEN_BOOT_RDY
)
195 }while(check_bootOk_time
--);
197 if(!(CPU_status
&CPU_GEN_BOOT_RDY
)) {
198 goto CPUCheckMainCodeOKAndTurnOnCPU_Fail
;
200 RT_TRACE(COMP_FIRMWARE
, "Download Firmware: Boot ready!\n");
205 CPUCheckMainCodeOKAndTurnOnCPU_Fail
:
206 RT_TRACE(COMP_ERR
, "ERR in %s()\n", __FUNCTION__
);
211 bool CPUcheck_firmware_ready(struct net_device
*dev
)
214 bool rt_status
= true;
215 int check_time
= 200000;
218 /* Check Firmware Ready */
220 CPU_status
= read_nic_dword(dev
, CPU_GEN
);
222 if(CPU_status
&CPU_GEN_FIRM_RDY
)
225 }while(check_time
--);
227 if(!(CPU_status
&CPU_GEN_FIRM_RDY
))
228 goto CPUCheckFirmwareReady_Fail
;
230 RT_TRACE(COMP_FIRMWARE
, "Download Firmware: Firmware ready!\n");
234 CPUCheckFirmwareReady_Fail
:
235 RT_TRACE(COMP_ERR
, "ERR in %s()\n", __FUNCTION__
);
241 bool init_firmware(struct net_device
*dev
)
243 struct r8192_priv
*priv
= ieee80211_priv(dev
);
244 bool rt_status
= TRUE
;
247 u8
*firmware_img_buf
[3] = { &rtl8190_fwboot_array
[0],
248 &rtl8190_fwmain_array
[0],
249 &rtl8190_fwdata_array
[0]};
251 u32 firmware_img_len
[3] = { sizeof(rtl8190_fwboot_array
),
252 sizeof(rtl8190_fwmain_array
),
253 sizeof(rtl8190_fwdata_array
)};
255 u8
*firmware_img_buf
[3] = { &rtl8192e_fwboot_array
[0],
256 &rtl8192e_fwmain_array
[0],
257 &rtl8192e_fwdata_array
[0]};
259 u32 firmware_img_len
[3] = { sizeof(rtl8192e_fwboot_array
),
260 sizeof(rtl8192e_fwmain_array
),
261 sizeof(rtl8192e_fwdata_array
)};
264 u8
*mapped_file
= NULL
;
266 opt_rst_type_e rst_opt
= OPT_SYSTEM_RESET
;
267 firmware_init_step_e starting_state
= FW_INIT_STEP0_BOOT
;
269 rt_firmware
*pfirmware
= priv
->pFirmware
;
270 const struct firmware
*fw_entry
;
272 const char *fw_name
[3] = { "RTL8190P/boot.img",
274 "RTL8190P/data.img"};
277 const char *fw_name
[3] = { "RTL8192E/boot.img",
279 "RTL8192E/data.img"};
283 RT_TRACE(COMP_FIRMWARE
, " PlatformInitFirmware()==>\n");
285 if (pfirmware
->firmware_status
== FW_STATUS_0_INIT
) {
286 /* it is called by reset */
287 rst_opt
= OPT_SYSTEM_RESET
;
288 starting_state
= FW_INIT_STEP0_BOOT
;
289 // TODO: system reset
291 }else if(pfirmware
->firmware_status
== FW_STATUS_5_READY
) {
292 /* it is called by Initialize */
293 rst_opt
= OPT_FIRMWARE_RESET
;
294 starting_state
= FW_INIT_STEP2_DATA
;
296 RT_TRACE(COMP_FIRMWARE
, "PlatformInitFirmware: undefined firmware state\n");
300 * Download boot, main, and data image for System reset.
301 * Download data image for firmware reseta
303 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
304 priv
->firmware_source
= FW_SOURCE_HEADER_FILE
;
306 priv
->firmware_source
= FW_SOURCE_IMG_FILE
;
308 for(init_step
= starting_state
; init_step
<= FW_INIT_STEP2_DATA
; init_step
++) {
310 * Open Image file, and map file to contineous memory if open file success.
311 * or read image file from array. Default load from IMG file
313 if(rst_opt
== OPT_SYSTEM_RESET
) {
314 switch(priv
->firmware_source
) {
315 case FW_SOURCE_IMG_FILE
:
317 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
318 if(pfirmware
->firmware_buf_size
[init_step
] == 0) {
319 rc
= request_firmware(&fw_entry
, fw_name
[init_step
],&priv
->pdev
->dev
);
321 RT_TRACE(COMP_FIRMWARE
, "request firmware fail!\n");
322 goto download_firmware_fail
;
325 if(fw_entry
->size
> sizeof(pfirmware
->firmware_buf
[init_step
])) {
326 RT_TRACE(COMP_FIRMWARE
, "img file size exceed the container buffer fail!\n");
327 goto download_firmware_fail
;
330 if(init_step
!= FW_INIT_STEP1_MAIN
) {
331 memcpy(pfirmware
->firmware_buf
[init_step
],fw_entry
->data
,fw_entry
->size
);
332 pfirmware
->firmware_buf_size
[init_step
] = fw_entry
->size
;
336 memcpy(pfirmware
->firmware_buf
[init_step
],fw_entry
->data
,fw_entry
->size
);
337 pfirmware
->firmware_buf_size
[init_step
] = fw_entry
->size
;
340 memset(pfirmware
->firmware_buf
[init_step
],0,128);
341 memcpy(&pfirmware
->firmware_buf
[init_step
][128],fw_entry
->data
,fw_entry
->size
);
342 //mapped_file = pfirmware->firmware_buf[init_step];
343 pfirmware
->firmware_buf_size
[init_step
] = fw_entry
->size
+128;
344 //file_length = fw_entry->size + 128;
347 //pfirmware->firmware_buf_size = file_length;
349 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
350 if(rst_opt
== OPT_SYSTEM_RESET
) {
351 release_firmware(fw_entry
);
355 mapped_file
= pfirmware
->firmware_buf
[init_step
];
356 file_length
= pfirmware
->firmware_buf_size
[init_step
];
360 case FW_SOURCE_HEADER_FILE
:
361 mapped_file
= firmware_img_buf
[init_step
];
362 file_length
= firmware_img_len
[init_step
];
363 if(init_step
== FW_INIT_STEP2_DATA
) {
364 memcpy(pfirmware
->firmware_buf
[init_step
], mapped_file
, file_length
);
365 pfirmware
->firmware_buf_size
[init_step
] = file_length
;
374 }else if(rst_opt
== OPT_FIRMWARE_RESET
) {
375 /* we only need to download data.img here */
376 mapped_file
= pfirmware
->firmware_buf
[init_step
];
377 file_length
= pfirmware
->firmware_buf_size
[init_step
];
380 /* Download image file */
381 /* The firmware download process is just as following,
382 * 1. that is each packet will be segmented and inserted to the wait queue.
383 * 2. each packet segment will be put in the skb_buff packet.
384 * 3. each skb_buff packet data content will already include the firmware info
385 * and Tx descriptor info
387 rt_status
= fw_download_code(dev
,mapped_file
,file_length
);
388 if(rt_status
!= TRUE
) {
389 goto download_firmware_fail
;
393 case FW_INIT_STEP0_BOOT
:
395 * initialize command descriptor.
396 * will set polling bit when firmware code is also configured
398 pfirmware
->firmware_status
= FW_STATUS_1_MOVE_BOOT_CODE
;
400 // To initialize IMEM, CPU move code from 0x80000080, hence, we send 0x80 byte packet
401 rt_status
= fwSendNullPacket(dev
, RTL8190_CPU_START_OFFSET
);
402 if(rt_status
!= true)
404 RT_TRACE(COMP_INIT
, "fwSendNullPacket() fail ! \n");
405 goto download_firmware_fail
;
410 * To initialize IMEM, CPU move code from 0x80000080,
411 * hence, we send 0x80 byte packet
415 case FW_INIT_STEP1_MAIN
:
416 /* Download firmware code. Wait until Boot Ready and Turn on CPU */
417 pfirmware
->firmware_status
= FW_STATUS_2_MOVE_MAIN_CODE
;
419 /* Check Put Code OK and Turn On CPU */
420 rt_status
= CPUcheck_maincodeok_turnonCPU(dev
);
421 if(rt_status
!= TRUE
) {
422 RT_TRACE(COMP_FIRMWARE
, "CPUcheck_maincodeok_turnonCPU fail!\n");
423 goto download_firmware_fail
;
426 pfirmware
->firmware_status
= FW_STATUS_3_TURNON_CPU
;
429 case FW_INIT_STEP2_DATA
:
430 /* download initial data code */
431 pfirmware
->firmware_status
= FW_STATUS_4_MOVE_DATA_CODE
;
434 rt_status
= CPUcheck_firmware_ready(dev
);
435 if(rt_status
!= TRUE
) {
436 RT_TRACE(COMP_FIRMWARE
, "CPUcheck_firmware_ready fail(%d)!\n",rt_status
);
437 goto download_firmware_fail
;
440 /* wait until data code is initialized ready.*/
441 pfirmware
->firmware_status
= FW_STATUS_5_READY
;
446 RT_TRACE(COMP_FIRMWARE
, "Firmware Download Success\n");
447 //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n"));
451 download_firmware_fail
:
452 RT_TRACE(COMP_ERR
, "ERR in %s()\n", __FUNCTION__
);
460 * Procedure: (1) Transform firmware code from little endian to big endian if required.
461 * (2) Number of bytes in Firmware downloading should be multiple
462 * of 4 bytes. If length is not multiple of 4 bytes, appending of zeros is required
465 void CmdAppendZeroAndEndianTransform(
471 u2Byte ulAppendBytes
= 0, i
;
472 u2Byte ulLength
= *pLength
;
475 //memset(pDst, 0xcc, 12);
478 /* Transform from little endian to big endian */
479 //#if DEV_BUS_TYPE==PCI_INTERFACE
481 for( i
=0 ; i
<(*pLength
) ; i
+=4)
483 if((i
+3) < (*pLength
)) pDst
[i
+0] = pSrc
[i
+3];
484 if((i
+2) < (*pLength
)) pDst
[i
+1] = pSrc
[i
+2];
485 if((i
+1) < (*pLength
)) pDst
[i
+2] = pSrc
[i
+1];
486 if((i
+0) < (*pLength
)) pDst
[i
+3] = pSrc
[i
+0];
489 pDst
+= USB_HWDESC_HEADER_LEN
;
490 ulLength
-= USB_HWDESC_HEADER_LEN
;
492 for( i
=0 ; i
<ulLength
; i
+=4) {
493 if((i
+3) < ulLength
) pDst
[i
+0] = pSrc
[i
+3];
494 if((i
+2) < ulLength
) pDst
[i
+1] = pSrc
[i
+2];
495 if((i
+1) < ulLength
) pDst
[i
+2] = pSrc
[i
+1];
496 if((i
+0) < ulLength
) pDst
[i
+3] = pSrc
[i
+0];
502 if( ((*pLength
) % 4) >0)
504 ulAppendBytes
= 4-((*pLength
) % 4);
506 for(i
=0 ; i
<ulAppendBytes
; i
++)
507 pDst
[ 4*((*pLength
)/4) + i
] = 0x0;
509 *pLength
+= ulAppendBytes
;
519 PRT_TX_LOCAL_BUFFER pBuf
,
522 BOOLEAN bLastInitPacket
527 u2Byte firstDesc
,curDesc
= 0;
528 u2Byte FragIndex
=0, FragBufferIndex
=0;
530 RT_STATUS rtStatus
= RT_STATUS_SUCCESS
;
532 CmdInitTCB(Adapter
, pTcb
, pBuf
, BufferLen
);
535 if(CmdCheckFragment(Adapter
, pTcb
, pBuf
))
536 CmdFragmentTCB(Adapter
, pTcb
);
538 pTcb
->FragLength
[0] = (u2Byte
)pTcb
->BufferList
[0].Length
;
540 QueueID
=pTcb
->SpecifiedQueueID
;
541 #if DEV_BUS_TYPE!=USB_INTERFACE
542 firstDesc
=curDesc
=Adapter
->NextTxDescToFill
[QueueID
];
545 #if DEV_BUS_TYPE!=USB_INTERFACE
546 if(VacancyTxDescNum(Adapter
, QueueID
) > pTcb
->BufferCount
)
548 if(PlatformIsTxQueueAvailable(Adapter
, QueueID
, pTcb
->BufferCount
) &&
549 RTIsListEmpty(&Adapter
->TcbWaitQueue
[QueueID
]))
554 for(i
=0 ; i
<pTcb
->BufferCount
; i
++)
556 Adapter
->HalFunc
.TxFillCmdDescHandler(
559 QueueID
, //QueueIndex
561 FragBufferIndex
==0, //bFirstSeg
562 FragBufferIndex
==(pTcb
->FragBufCount
[FragIndex
]-1), //bLastSeg
563 pTcb
->BufferList
[i
].VirtualAddress
, //VirtualAddress
564 pTcb
->BufferList
[i
].PhysicalAddressLow
, //PhyAddressLow
565 pTcb
->BufferList
[i
].Length
, //BufferLen
567 (i
==(pTcb
->BufferCount
-1)) && bLastInitPacket
, //bLastInitPacket
568 PacketType
, //DescPacketType
569 pTcb
->FragLength
[FragIndex
] //PktLen
572 if(FragBufferIndex
==(pTcb
->FragBufCount
[FragIndex
]-1))
573 { // Last segment of the fragment.
578 if(FragBufferIndex
==pTcb
->FragBufCount
[FragIndex
])
584 #if DEV_BUS_TYPE!=USB_INTERFACE
585 curDesc
=(curDesc
+1)%Adapter
->NumTxDesc
[QueueID
];
590 #if DEV_BUS_TYPE!=USB_INTERFACE
591 RTInsertTailList(&Adapter
->TcbBusyQueue
[QueueID
], &pTcb
->List
);
592 IncrementTxDescToFill(Adapter
, QueueID
, pTcb
->nDescUsed
);
593 Adapter
->HalFunc
.SetTxDescOWNHandler(Adapter
, QueueID
, firstDesc
);
594 // TODO: should call poll use QueueID
595 Adapter
->HalFunc
.TxPollingHandler(Adapter
, TXCMD_QUEUE
);
599 #if DEV_BUS_TYPE!=USB_INTERFACE
600 goto CmdSendPacket_Fail
;
603 pTcb
->bLastInitPacket
= bLastInitPacket
;
604 RTInsertTailList(&Adapter
->TcbWaitQueue
[pTcb
->SpecifiedQueueID
], &pTcb
->List
);
610 #if DEV_BUS_TYPE!=USB_INTERFACE
612 rtStatus
= RT_STATUS_FAILURE
;
629 RT_STATUS rtStatus
= RT_STATUS_SUCCESS
;
633 PRT_TX_LOCAL_BUFFER pBuf
;
634 BOOLEAN bLastInitPacket
= FALSE
;
636 PlatformAcquireSpinLock(Adapter
, RT_TX_SPINLOCK
);
638 #if DEV_BUS_TYPE==USB_INTERFACE
639 Length
+= USB_HWDESC_HEADER_LEN
;
642 //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
643 if(MgntGetBuffer(Adapter
, &pTcb
, &pBuf
))
645 PlatformZeroMemory(pBuf
->Buffer
.VirtualAddress
, Length
);
646 rtStatus
= CmdSendPacket(Adapter
, pTcb
, pBuf
, Length
, DESC_PACKET_TYPE_INIT
, bLastInitPacket
); //0 : always set LastInitPacket to zero
647 //#if HAL_CODE_BASE != RTL8190HW
648 // // TODO: for test only
649 // ReturnTCB(Adapter, pTcb, RT_STATUS_SUCCESS);
651 if(rtStatus
== RT_STATUS_FAILURE
)
652 goto CmdSendNullPacket_Fail
;
654 goto CmdSendNullPacket_Fail
;
656 PlatformReleaseSpinLock(Adapter
, RT_TX_SPINLOCK
);
660 CmdSendNullPacket_Fail
:
661 PlatformReleaseSpinLock(Adapter
, RT_TX_SPINLOCK
);
662 rtStatus
= RT_STATUS_FAILURE
;
663 RT_ASSERT(rtStatus
== RT_STATUS_SUCCESS
, ("CmdSendDownloadCode fail !!\n"));