linux/drivers/staging/rtl8192u/r819xU_firmware.c
<<
>>
Prefs
   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                skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
  65                if (!skb)
  66                        return false;
  67                memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
  68                tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
  69                tcb_desc->queue_index = TXCMD_QUEUE;
  70                tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
  71                tcb_desc->bLastIniPkt = bLastIniPkt;
  72
  73                skb_reserve(skb, USB_HWDESC_HEADER_LEN);
  74                seg_ptr = skb->data;
  75                /*
  76                 * Transform from little endian to big endian
  77                 * and pending  zero
  78                 */
  79                for(i=0 ; i < frag_length; i+=4) {
  80                        *seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
  81                        *seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
  82                        *seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
  83                        *seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
  84                }
  85                tcb_desc->txbuf_size= (u16)i;
  86                skb_put(skb, i);
  87
  88                if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
  89                        (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
  90                        (priv->ieee80211->queue_stop) ) {
  91                        RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
  92                        skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
  93                } else {
  94                        priv->ieee80211->softmac_hard_start_xmit(skb,dev);
  95                }
  96
  97                code_virtual_address += frag_length;
  98                frag_offset += frag_length;
  99
 100        }while(frag_offset < buffer_len);
 101
 102        return rt_status;
 103
 104}
 105
 106bool
 107fwSendNullPacket(
 108        struct net_device *dev,
 109        u32                     Length
 110)
 111{
 112        bool    rtStatus = true;
 113        struct r8192_priv   *priv = ieee80211_priv(dev);
 114        struct sk_buff      *skb;
 115        cb_desc             *tcb_desc;
 116        unsigned char       *ptr_buf;
 117        bool    bLastInitPacket = false;
 118
 119        //PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
 120
 121        //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
 122        skb  = dev_alloc_skb(Length+ 4);
 123        memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
 124        tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 125        tcb_desc->queue_index = TXCMD_QUEUE;
 126        tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
 127        tcb_desc->bLastIniPkt = bLastInitPacket;
 128        ptr_buf = skb_put(skb, Length);
 129        memset(ptr_buf,0,Length);
 130        tcb_desc->txbuf_size= (u16)Length;
 131
 132        if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
 133                        (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
 134                        (priv->ieee80211->queue_stop) ) {
 135                        RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
 136                        skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
 137                } else {
 138                        priv->ieee80211->softmac_hard_start_xmit(skb,dev);
 139                }
 140
 141        //PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
 142        return rtStatus;
 143}
 144
 145
 146//-----------------------------------------------------------------------------
 147// Procedure:    Check whether main code is download OK. If OK, turn on CPU
 148//
 149// Description:   CPU register locates in different page against general register.
 150//                          Switch to CPU register in the begin and switch back before return
 151//
 152//
 153// Arguments:   The pointer of the adapter
 154//
 155// Returns:
 156//        NDIS_STATUS_FAILURE - the following initialization process should be terminated
 157//        NDIS_STATUS_SUCCESS - if firmware initialization process success
 158//-----------------------------------------------------------------------------
 159bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev)
 160{
 161        bool            rt_status = true;
 162        int             check_putcodeOK_time = 200000, check_bootOk_time = 200000;
 163        u32             CPU_status = 0;
 164
 165        /* Check whether put code OK */
 166        do {
 167                read_nic_dword(dev, CPU_GEN, &CPU_status);
 168
 169                if (CPU_status&CPU_GEN_PUT_CODE_OK)
 170                        break;
 171
 172        }while(check_putcodeOK_time--);
 173
 174        if (!(CPU_status&CPU_GEN_PUT_CODE_OK)) {
 175                RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n");
 176                goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
 177        } else {
 178                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n");
 179        }
 180
 181        /* Turn On CPU */
 182        read_nic_dword(dev, CPU_GEN, &CPU_status);
 183        write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff));
 184        mdelay(1000);
 185
 186        /* Check whether CPU boot OK */
 187        do {
 188                read_nic_dword(dev, CPU_GEN, &CPU_status);
 189
 190                if (CPU_status&CPU_GEN_BOOT_RDY)
 191                        break;
 192        }while(check_bootOk_time--);
 193
 194        if (!(CPU_status&CPU_GEN_BOOT_RDY)) {
 195                goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
 196        } else {
 197                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n");
 198        }
 199
 200        return rt_status;
 201
 202CPUCheckMainCodeOKAndTurnOnCPU_Fail:
 203        RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
 204        rt_status = FALSE;
 205        return rt_status;
 206}
 207
 208bool CPUcheck_firmware_ready(struct net_device *dev)
 209{
 210
 211        bool            rt_status = true;
 212        int             check_time = 200000;
 213        u32             CPU_status = 0;
 214
 215        /* Check Firmware Ready */
 216        do {
 217                read_nic_dword(dev, CPU_GEN, &CPU_status);
 218
 219                if (CPU_status&CPU_GEN_FIRM_RDY)
 220                        break;
 221
 222        }while(check_time--);
 223
 224        if (!(CPU_status&CPU_GEN_FIRM_RDY))
 225                goto CPUCheckFirmwareReady_Fail;
 226        else
 227                RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n");
 228
 229        return rt_status;
 230
 231CPUCheckFirmwareReady_Fail:
 232        RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
 233        rt_status = false;
 234        return rt_status;
 235
 236}
 237
 238bool init_firmware(struct net_device *dev)
 239{
 240        struct r8192_priv       *priv = ieee80211_priv(dev);
 241        bool                    rt_status = TRUE;
 242
 243        u32                     file_length = 0;
 244        u8                      *mapped_file = NULL;
 245        u32                     init_step = 0;
 246        opt_rst_type_e  rst_opt = OPT_SYSTEM_RESET;
 247        firmware_init_step_e    starting_state = FW_INIT_STEP0_BOOT;
 248
 249        rt_firmware             *pfirmware = priv->pFirmware;
 250        const struct firmware   *fw_entry;
 251        const char *fw_name[3] = { "RTL8192U/boot.img",
 252                           "RTL8192U/main.img",
 253                           "RTL8192U/data.img"};
 254        int rc;
 255
 256        RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n");
 257
 258        if (pfirmware->firmware_status == FW_STATUS_0_INIT ) {
 259                /* it is called by reset */
 260                rst_opt = OPT_SYSTEM_RESET;
 261                starting_state = FW_INIT_STEP0_BOOT;
 262                // TODO: system reset
 263
 264        }else if (pfirmware->firmware_status == FW_STATUS_5_READY) {
 265                /* it is called by Initialize */
 266                rst_opt = OPT_FIRMWARE_RESET;
 267                starting_state = FW_INIT_STEP2_DATA;
 268        }else {
 269                 RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n");
 270        }
 271
 272        /*
 273         * Download boot, main, and data image for System reset.
 274         * Download data image for firmware reset
 275         */
 276        for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
 277                /*
 278                 * Open image file, and map file to continuous memory if open file success.
 279                 * or read image file from array. Default load from IMG file
 280                 */
 281                if (rst_opt == OPT_SYSTEM_RESET) {
 282                        rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev);
 283                        if (rc < 0 ) {
 284                                RT_TRACE(COMP_ERR, "request firmware fail!\n");
 285                                goto download_firmware_fail;
 286                        }
 287
 288                        if (fw_entry->size > sizeof(pfirmware->firmware_buf)) {
 289                                RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n");
 290                                goto download_firmware_fail;
 291                        }
 292
 293                        if (init_step != FW_INIT_STEP1_MAIN) {
 294                                memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size);
 295                                mapped_file = pfirmware->firmware_buf;
 296                                file_length = fw_entry->size;
 297                        } else {
 298                                memset(pfirmware->firmware_buf,0,128);
 299                                memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size);
 300                                mapped_file = pfirmware->firmware_buf;
 301                                file_length = fw_entry->size + 128;
 302                        }
 303                        pfirmware->firmware_buf_size = file_length;
 304                }else if (rst_opt == OPT_FIRMWARE_RESET ) {
 305                        /* we only need to download data.img here */
 306                        mapped_file = pfirmware->firmware_buf;
 307                        file_length = pfirmware->firmware_buf_size;
 308                }
 309
 310                /* Download image file */
 311                /* The firmware download process is just as following,
 312                 * 1. that is each packet will be segmented and inserted to the wait queue.
 313                 * 2. each packet segment will be put in the skb_buff packet.
 314                 * 3. each skb_buff packet data content will already include the firmware info
 315                 *   and Tx descriptor info
 316                 * */
 317                rt_status = fw_download_code(dev,mapped_file,file_length);
 318                if (rst_opt == OPT_SYSTEM_RESET) {
 319                        release_firmware(fw_entry);
 320                }
 321
 322                if (rt_status != TRUE) {
 323                        goto download_firmware_fail;
 324                }
 325
 326                switch (init_step) {
 327                case FW_INIT_STEP0_BOOT:
 328                        /* Download boot
 329                         * initialize command descriptor.
 330                         * will set polling bit when firmware code is also configured
 331                         */
 332                        pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE;
 333                        //mdelay(1000);
 334                        /*
 335                         * To initialize IMEM, CPU move code  from 0x80000080,
 336                         * hence, we send 0x80 byte packet
 337                         */
 338                        break;
 339
 340                case FW_INIT_STEP1_MAIN:
 341                        /* Download firmware code. Wait until Boot Ready and Turn on CPU */
 342                        pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE;
 343
 344                        /* Check Put Code OK and Turn On CPU */
 345                        rt_status = CPUcheck_maincodeok_turnonCPU(dev);
 346                        if (rt_status != TRUE) {
 347                                RT_TRACE(COMP_ERR, "CPUcheck_maincodeok_turnonCPU fail!\n");
 348                                goto download_firmware_fail;
 349                        }
 350
 351                        pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU;
 352                        break;
 353
 354                case FW_INIT_STEP2_DATA:
 355                        /* download initial data code */
 356                        pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE;
 357                        mdelay(1);
 358
 359                        rt_status = CPUcheck_firmware_ready(dev);
 360                        if (rt_status != TRUE) {
 361                                RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status);
 362                                goto download_firmware_fail;
 363                        }
 364
 365                        /* wait until data code is initialized ready.*/
 366                        pfirmware->firmware_status = FW_STATUS_5_READY;
 367                        break;
 368                }
 369        }
 370
 371        RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n");
 372        //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n"));
 373
 374        return rt_status;
 375
 376download_firmware_fail:
 377        RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__);
 378        rt_status = FALSE;
 379        return rt_status;
 380
 381}
 382
 383MODULE_FIRMWARE("RTL8192U/boot.img");
 384MODULE_FIRMWARE("RTL8192U/main.img");
 385MODULE_FIRMWARE("RTL8192U/data.img");
 386