iwlagn: prepare for new firmware file format
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-agn.c
index 5cf3822..65ae636 100644 (file)
@@ -1534,6 +1534,91 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
                                       iwl_ucode_callback);
 }
 
+struct iwlagn_firmware_pieces {
+       const void *inst, *data, *init, *init_data, *boot;
+       size_t inst_size, data_size, init_size, init_data_size, boot_size;
+
+       u32 build;
+};
+
+static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+                                      const struct firmware *ucode_raw,
+                                      struct iwlagn_firmware_pieces *pieces)
+{
+       struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+       u32 api_ver, hdr_size;
+       const u8 *src;
+
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(priv->ucode_ver);
+
+       switch (api_ver) {
+       default:
+               /*
+                * 4965 doesn't revision the firmware file format
+                * along with the API version, it always uses v1
+                * file format.
+                */
+               if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
+                               CSR_HW_REV_TYPE_4965) {
+                       hdr_size = 28;
+                       if (ucode_raw->size < hdr_size) {
+                               IWL_ERR(priv, "File size too small!\n");
+                               return -EINVAL;
+                       }
+                       pieces->build = le32_to_cpu(ucode->u.v2.build);
+                       pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+                       pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+                       pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+                       pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+                       pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
+                       src = ucode->u.v2.data;
+                       break;
+               }
+               /* fall through for 4965 */
+       case 0:
+       case 1:
+       case 2:
+               hdr_size = 24;
+               if (ucode_raw->size < hdr_size) {
+                       IWL_ERR(priv, "File size too small!\n");
+                       return -EINVAL;
+               }
+               pieces->build = 0;
+               pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+               pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+               pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+               pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
+               pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
+               src = ucode->u.v1.data;
+               break;
+       }
+
+       /* Verify size of file vs. image size info in file's header */
+       if (ucode_raw->size != hdr_size + pieces->inst_size +
+                               pieces->data_size + pieces->init_size +
+                               pieces->init_data_size + pieces->boot_size) {
+
+               IWL_ERR(priv,
+                       "uCode file size %d does not match expected size\n",
+                       (int)ucode_raw->size);
+               return -EINVAL;
+       }
+
+       pieces->inst = src;
+       src += pieces->inst_size;
+       pieces->data = src;
+       src += pieces->data_size;
+       pieces->init = src;
+       src += pieces->init_size;
+       pieces->init_data = src;
+       src += pieces->init_data_size;
+       pieces->boot = src;
+       src += pieces->boot_size;
+
+       return 0;
+}
+
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -1544,14 +1629,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 {
        struct iwl_priv *priv = context;
        struct iwl_ucode_header *ucode;
+       int err;
+       struct iwlagn_firmware_pieces pieces;
        const unsigned int api_max = priv->cfg->ucode_api_max;
        const unsigned int api_min = priv->cfg->ucode_api_min;
-       u8 *src;
-       size_t len;
-       u32 api_ver, build;
-       u32 inst_size, data_size, init_size, init_data_size, boot_size;
-       int err;
-       u16 eeprom_ver;
+       u32 api_ver;
+       char buildstr[25];
+       u32 build;
+
+       memset(&pieces, 0, sizeof(pieces));
 
        if (!ucode_raw) {
                IWL_ERR(priv, "request for firmware file '%s' failed.\n",
@@ -1562,8 +1648,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
                       priv->firmware_name, ucode_raw->size);
 
-       /* Make sure that we got at least the v1 header! */
-       if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
+       /* Make sure that we got at least the API version number */
+       if (ucode_raw->size < 4) {
                IWL_ERR(priv, "File size way too small!\n");
                goto try_again;
        }
@@ -1571,21 +1657,22 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Data from ucode file:  header followed by uCode images */
        ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
-       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       if (ucode->ver)
+               err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+       else
+               err = -EINVAL;
+
+       if (err)
+               goto try_again;
+
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
-       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
-       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
-       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
-       init_data_size =
-               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
-       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
-       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
-
-       /* api_ver should match the api version forming part of the
-        * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firmware header from here on forward */
+       build = pieces.build;
 
+       /*
+        * api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+        * on the API version read from firmware header from here on forward
+        */
        if (api_ver < api_min || api_ver > api_max) {
                IWL_ERR(priv, "Driver unable to support your firmware API. "
                          "Driver supports v%u, firmware is v%u.\n",
@@ -1599,40 +1686,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                          "from http://www.intellinuxwireless.org.\n",
                          api_max, api_ver);
 
-       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u\n",
-              IWL_UCODE_MAJOR(priv->ucode_ver),
-              IWL_UCODE_MINOR(priv->ucode_ver),
-              IWL_UCODE_API(priv->ucode_ver),
-              IWL_UCODE_SERIAL(priv->ucode_ver));
+       if (build)
+               sprintf(buildstr, " build %u", build);
+       else
+               buildstr[0] = '\0';
+
+       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
+                IWL_UCODE_MAJOR(priv->ucode_ver),
+                IWL_UCODE_MINOR(priv->ucode_ver),
+                IWL_UCODE_API(priv->ucode_ver),
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        snprintf(priv->hw->wiphy->fw_version,
                 sizeof(priv->hw->wiphy->fw_version),
-                "%u.%u.%u.%u",
+                "%u.%u.%u.%u%s",
                 IWL_UCODE_MAJOR(priv->ucode_ver),
                 IWL_UCODE_MINOR(priv->ucode_ver),
                 IWL_UCODE_API(priv->ucode_ver),
-                IWL_UCODE_SERIAL(priv->ucode_ver));
-
-       if (build)
-               IWL_DEBUG_INFO(priv, "Build %u\n", build);
-
-       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-       IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-                      ? "OTP" : "EEPROM", eeprom_ver);
-
-       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-                      priv->ucode_ver);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
-                      inst_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n",
-                      data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n",
-                      init_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n",
-                      init_data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
-                      boot_size);
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        /*
         * For any of the failures below (before allocating pci memory)
@@ -1640,58 +1713,63 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
         * user just got a corrupted version of the latest API.
         */
 
-       /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size !=
-               priv->cfg->ops->ucode->get_header_size(api_ver) +
-               inst_size + data_size + init_size +
-               init_data_size + boot_size) {
-
-               IWL_DEBUG_INFO(priv,
-                       "uCode file size %d does not match expected size\n",
-                       (int)ucode_raw->size);
-               goto try_again;
-       }
+       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+                      priv->ucode_ver);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+                      pieces.inst_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+                      pieces.data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+                      pieces.init_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+                      pieces.init_data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
+                      pieces.boot_size);
 
        /* Verify that uCode images will fit in card's SRAM */
-       if (inst_size > priv->hw_params.max_inst_size) {
-               IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
-                              inst_size);
+       if (pieces.inst_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+                       pieces.inst_size);
                goto try_again;
        }
 
-       if (data_size > priv->hw_params.max_data_size) {
-               IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
-                               data_size);
+       if (pieces.data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+                       pieces.data_size);
                goto try_again;
        }
-       if (init_size > priv->hw_params.max_inst_size) {
-               IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
-                       init_size);
+
+       if (pieces.init_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+                       pieces.init_size);
                goto try_again;
        }
-       if (init_data_size > priv->hw_params.max_data_size) {
-               IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
-                     init_data_size);
+
+       if (pieces.init_data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+                       pieces.init_data_size);
                goto try_again;
        }
-       if (boot_size > priv->hw_params.max_bsm_size) {
-               IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
-                       boot_size);
+
+       if (pieces.boot_size > priv->hw_params.max_bsm_size) {
+               IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
+                       pieces.boot_size);
                goto try_again;
        }
 
+
        /* Allocate ucode buffers for card's bus-master loading ... */
 
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       priv->ucode_code.len = inst_size;
+       priv->ucode_code.len = pieces.inst_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
-       priv->ucode_data.len = data_size;
+       priv->ucode_data.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
-       priv->ucode_data_backup.len = data_size;
+       priv->ucode_data_backup.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
        if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
@@ -1699,11 +1777,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
-       if (init_size && init_data_size) {
-               priv->ucode_init.len = init_size;
+       if (pieces.init_size && pieces.init_data_size) {
+               priv->ucode_init.len = pieces.init_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
 
-               priv->ucode_init_data.len = init_data_size;
+               priv->ucode_init_data.len = pieces.init_data_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
 
                if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
@@ -1711,8 +1789,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        }
 
        /* Bootstrap (instructions only, no data) */
-       if (boot_size) {
-               priv->ucode_boot.len = boot_size;
+       if (pieces.boot_size) {
+               priv->ucode_boot.len = pieces.boot_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
                if (!priv->ucode_boot.v_addr)
@@ -1722,44 +1800,41 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
-       len = inst_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
-       memcpy(priv->ucode_code.v_addr, src, len);
-       src += len;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
+                       pieces.inst_size);
+       memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
 
        IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
-       /* Runtime data (2nd block)
-        * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-       len = data_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
-       memcpy(priv->ucode_data.v_addr, src, len);
-       memcpy(priv->ucode_data_backup.v_addr, src, len);
-       src += len;
-
-       /* Initialization instructions (3rd block) */
-       if (init_size) {
-               len = init_size;
+       /*
+        * Runtime data
+        * NOTE:  Copy into backup buffer will be done in iwl_up()
+        */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
+                       pieces.data_size);
+       memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
+       memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
+
+       /* Initialization instructions */
+       if (pieces.init_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
-                               len);
-               memcpy(priv->ucode_init.v_addr, src, len);
-               src += len;
+                               pieces.init_size);
+               memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
        }
 
-       /* Initialization data (4th block) */
-       if (init_data_size) {
-               len = init_data_size;
+       /* Initialization data */
+       if (pieces.init_data_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
-                              len);
-               memcpy(priv->ucode_init_data.v_addr, src, len);
-               src += len;
+                              pieces.init_data_size);
+               memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
+                      pieces.init_data_size);
        }
 
-       /* Bootstrap instructions (5th block) */
-       len = boot_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
-       memcpy(priv->ucode_boot.v_addr, src, len);
+       /* Bootstrap instructions */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
+                       pieces.boot_size);
+       memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
 
        /**************************************************
         * This is still part of probe() in a sense...
@@ -2606,17 +2681,11 @@ void iwl_post_associate(struct iwl_priv *priv)
        switch (priv->iw_mode) {
        case NL80211_IFTYPE_STATION:
                break;
-
        case NL80211_IFTYPE_ADHOC:
-
                /* assume default assoc id */
                priv->assoc_id = 1;
-
-               iwl_add_local_station(priv, priv->bssid, true);
                iwl_send_beacon_cmd(priv);
-
                break;
-
        default:
                IWL_ERR(priv, "%s Should not be called in %d mode\n",
                          __func__, priv->iw_mode);