Skip to content

Commit

Permalink
iwlwifi: Handle new firmware file with ucode build number in header
Browse files Browse the repository at this point in the history
commit cc0f555 upstream.

Adding new API version to account for change to ucode file format.  New
header includes the build number of the ucode.  This build number is the
SVN revision thus allowing for exact correlation to the code that
generated it.

The header adds the build number so that older ucode images can also be
enhanced to include the build in the future.

some cleanup in iwl_read_ucode needed to ensure old header not used and
reduce unnecessary references through pointer with the data is already
in heap variable.

Signed-off-by: Jay Sternberg <jay.e.sternberg@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Jay Sternberg authored and gregkh committed Oct 5, 2009
1 parent 6b92d44 commit 7b70149
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 54 deletions.
40 changes: 40 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-3945.c
Expand Up @@ -2784,11 +2784,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}

#define IWL3945_UCODE_GET(item) \
static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
return le32_to_cpu(ucode->u.v1.item); \
}

static u32 iwl3945_ucode_get_header_size(u32 api_ver)
{
return UCODE_HEADER_SIZE(1);
}
static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return 0;
}
static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return (u8 *) ucode->u.v1.data;
}

IWL3945_UCODE_GET(inst_size);
IWL3945_UCODE_GET(data_size);
IWL3945_UCODE_GET(init_size);
IWL3945_UCODE_GET(init_data_size);
IWL3945_UCODE_GET(boot_size);

static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon,
};

static struct iwl_ucode_ops iwl3945_ucode = {
.get_header_size = iwl3945_ucode_get_header_size,
.get_build = iwl3945_ucode_get_build,
.get_inst_size = iwl3945_ucode_get_inst_size,
.get_data_size = iwl3945_ucode_get_data_size,
.get_init_size = iwl3945_ucode_get_init_size,
.get_init_data_size = iwl3945_ucode_get_init_data_size,
.get_boot_size = iwl3945_ucode_get_boot_size,
.get_data = iwl3945_ucode_get_data,
};

static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
Expand Down Expand Up @@ -2829,6 +2868,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};

static struct iwl_ops iwl3945_ops = {
.ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
Expand Down
39 changes: 39 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-4965.c
Expand Up @@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}

#define IWL4965_UCODE_GET(item) \
static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
return le32_to_cpu(ucode->u.v1.item); \
}

static u32 iwl4965_ucode_get_header_size(u32 api_ver)
{
return UCODE_HEADER_SIZE(1);
}
static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return 0;
}
static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return (u8 *) ucode->u.v1.data;
}

IWL4965_UCODE_GET(inst_size);
IWL4965_UCODE_GET(data_size);
IWL4965_UCODE_GET(init_size);
IWL4965_UCODE_GET(init_data_size);
IWL4965_UCODE_GET(boot_size);

static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
};

static struct iwl_ucode_ops iwl4965_ucode = {
.get_header_size = iwl4965_ucode_get_header_size,
.get_build = iwl4965_ucode_get_build,
.get_inst_size = iwl4965_ucode_get_inst_size,
.get_data_size = iwl4965_ucode_get_data_size,
.get_init_size = iwl4965_ucode_get_init_size,
.get_init_data_size = iwl4965_ucode_get_init_data_size,
.get_boot_size = iwl4965_ucode_get_boot_size,
.get_data = iwl4965_ucode_get_data,
};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
Expand Down Expand Up @@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};

static struct iwl_ops iwl4965_ops = {
.ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
Expand Down
51 changes: 51 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-5000.c
Expand Up @@ -1426,6 +1426,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}

#define IWL5000_UCODE_GET(item) \
static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
if (api_ver <= 2) \
return le32_to_cpu(ucode->u.v1.item); \
return le32_to_cpu(ucode->u.v2.item); \
}

static u32 iwl5000_ucode_get_header_size(u32 api_ver)
{
if (api_ver <= 2)
return UCODE_HEADER_SIZE(1);
return UCODE_HEADER_SIZE(2);
}

static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
if (api_ver <= 2)
return 0;
return le32_to_cpu(ucode->u.v2.build);
}

static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
if (api_ver <= 2)
return (u8 *) ucode->u.v1.data;
return (u8 *) ucode->u.v2.data;
}

IWL5000_UCODE_GET(inst_size);
IWL5000_UCODE_GET(data_size);
IWL5000_UCODE_GET(init_size);
IWL5000_UCODE_GET(init_data_size);
IWL5000_UCODE_GET(boot_size);

struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
Expand All @@ -1441,6 +1479,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi,
};

struct iwl_ucode_ops iwl5000_ucode = {
.get_header_size = iwl5000_ucode_get_header_size,
.get_build = iwl5000_ucode_get_build,
.get_inst_size = iwl5000_ucode_get_inst_size,
.get_data_size = iwl5000_ucode_get_data_size,
.get_init_size = iwl5000_ucode_get_init_size,
.get_init_data_size = iwl5000_ucode_get_init_data_size,
.get_boot_size = iwl5000_ucode_get_boot_size,
.get_data = iwl5000_ucode_get_data,
};

struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
Expand Down Expand Up @@ -1542,12 +1591,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};

struct iwl_ops iwl5000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};

static struct iwl_ops iwl5150_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-6000.c
Expand Up @@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"

/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 2
#define IWL6050_UCODE_API_MAX 2
#define IWL6000_UCODE_API_MAX 3
#define IWL6050_UCODE_API_MAX 3

/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
Expand All @@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};

static struct iwl_ops iwl6000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
Expand Down
55 changes: 32 additions & 23 deletions drivers/net/wireless/iwlwifi/iwl-agn.c
Expand Up @@ -1348,7 +1348,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
struct iwl_ucode *ucode;
struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
Expand All @@ -1357,7 +1357,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
u32 api_ver, build;
u32 inst_size, data_size, init_size, init_data_size, boot_size;

/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
Expand Down Expand Up @@ -1387,23 +1388,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;

/* Make sure that we got at least our header! */
if (ucode_raw->size < sizeof(*ucode)) {
/* Make sure that we got at least the v1 header! */
if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}

/* Data from ucode file: header followed by uCode images */
ucode = (void *)ucode_raw->data;
ucode = (struct iwl_ucode_header *)ucode_raw->data;

priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
inst_size = le32_to_cpu(ucode->inst_size);
data_size = le32_to_cpu(ucode->data_size);
init_size = le32_to_cpu(ucode->init_size);
init_data_size = le32_to_cpu(ucode->init_data_size);
boot_size = le32_to_cpu(ucode->boot_size);
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
Expand All @@ -1429,6 +1433,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));

if (build)
IWL_DEBUG_INFO(priv, "Build %u\n", build);

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",
Expand All @@ -1443,12 +1450,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);

/* Verify size of file vs. image size info in file's header */
if (ucode_raw->size < sizeof(*ucode) +
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 too small\n",
(int)ucode_raw->size);
IWL_DEBUG_INFO(priv,
"uCode file size %d does not match expected size\n",
(int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
Expand Down Expand Up @@ -1528,42 +1537,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */

/* Runtime instructions (first block of data in file) */
src = &ucode->data[0];
len = priv->ucode_code.len;
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, "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() */
src = &ucode->data[inst_size];
len = priv->ucode_data.len;
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) {
src = &ucode->data[inst_size + data_size];
len = priv->ucode_init.len;
len = 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;
}

/* Initialization data (4th block) */
if (init_data_size) {
src = &ucode->data[inst_size + data_size + init_size];
len = priv->ucode_init_data.len;
len = 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;
}

/* Bootstrap instructions (5th block) */
src = &ucode->data[inst_size + data_size + init_size + init_data_size];
len = priv->ucode_boot.len;
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);

Expand Down
12 changes: 12 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-core.h
Expand Up @@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv);
};

struct iwl_ucode_ops {
u32 (*get_header_size)(u32);
u32 (*get_build)(const struct iwl_ucode_header *, u32);
u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
u8 * (*get_data)(const struct iwl_ucode_header *, u32);
};

struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
Expand Down Expand Up @@ -171,6 +182,7 @@ struct iwl_lib_ops {
};

struct iwl_ops {
const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
Expand Down

0 comments on commit 7b70149

Please sign in to comment.