|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
|
|
|
+ * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
|
|
|
*
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
@@ -118,6 +118,12 @@ static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
|
|
|
return (int)dlen;
|
|
|
}
|
|
|
|
|
|
+static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
|
|
|
+ size_t size)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
|
|
size_t size)
|
|
|
{
|
|
@@ -126,6 +132,27 @@ static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
|
|
|
+ size_t size)
|
|
|
+{
|
|
|
+ const struct wil_fw_record_capabilities *rec = data;
|
|
|
+ size_t capa_size;
|
|
|
+
|
|
|
+ if (size < sizeof(*rec) ||
|
|
|
+ le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ capa_size = size - offsetof(struct wil_fw_record_capabilities,
|
|
|
+ capabilities);
|
|
|
+ bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
|
|
|
+ memcpy(wil->fw_capabilities, rec->capabilities,
|
|
|
+ min(sizeof(wil->fw_capabilities), capa_size));
|
|
|
+ wil_hex_dump_fw("CAPA", DUMP_PREFIX_OFFSET, 16, 1,
|
|
|
+ rec->capabilities, capa_size, false);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
|
|
size_t size)
|
|
|
{
|
|
@@ -383,42 +410,51 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
|
|
|
|
|
|
static const struct {
|
|
|
int type;
|
|
|
- int (*handler)(struct wil6210_priv *wil, const void *data, size_t size);
|
|
|
+ int (*load_handler)(struct wil6210_priv *wil, const void *data,
|
|
|
+ size_t size);
|
|
|
+ int (*parse_handler)(struct wil6210_priv *wil, const void *data,
|
|
|
+ size_t size);
|
|
|
} wil_fw_handlers[] = {
|
|
|
- {wil_fw_type_comment, fw_handle_comment},
|
|
|
- {wil_fw_type_data, fw_handle_data},
|
|
|
- {wil_fw_type_fill, fw_handle_fill},
|
|
|
+ {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
|
|
|
+ {wil_fw_type_data, fw_handle_data, fw_ignore_section},
|
|
|
+ {wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
|
|
|
/* wil_fw_type_action */
|
|
|
/* wil_fw_type_verify */
|
|
|
- {wil_fw_type_file_header, fw_handle_file_header},
|
|
|
- {wil_fw_type_direct_write, fw_handle_direct_write},
|
|
|
- {wil_fw_type_gateway_data, fw_handle_gateway_data},
|
|
|
- {wil_fw_type_gateway_data4, fw_handle_gateway_data4},
|
|
|
+ {wil_fw_type_file_header, fw_handle_file_header,
|
|
|
+ fw_handle_file_header},
|
|
|
+ {wil_fw_type_direct_write, fw_handle_direct_write, fw_ignore_section},
|
|
|
+ {wil_fw_type_gateway_data, fw_handle_gateway_data, fw_ignore_section},
|
|
|
+ {wil_fw_type_gateway_data4, fw_handle_gateway_data4,
|
|
|
+ fw_ignore_section},
|
|
|
};
|
|
|
|
|
|
static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
|
|
|
- const void *data, size_t size)
|
|
|
+ const void *data, size_t size, bool load)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++)
|
|
|
if (wil_fw_handlers[i].type == type)
|
|
|
- return wil_fw_handlers[i].handler(wil, data, size);
|
|
|
- }
|
|
|
+ return load ?
|
|
|
+ wil_fw_handlers[i].load_handler(
|
|
|
+ wil, data, size) :
|
|
|
+ wil_fw_handlers[i].parse_handler(
|
|
|
+ wil, data, size);
|
|
|
|
|
|
wil_err_fw(wil, "unknown record type: %d\n", type);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * wil_fw_load - load FW into device
|
|
|
- *
|
|
|
- * Load the FW and uCode code and data to the corresponding device
|
|
|
- * memory regions
|
|
|
+ * wil_fw_process - process section from FW file
|
|
|
+ * if load is true: Load the FW and uCode code and data to the
|
|
|
+ * corresponding device memory regions,
|
|
|
+ * otherwise only parse and look for capabilities
|
|
|
*
|
|
|
* Return error code
|
|
|
*/
|
|
|
-static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
|
|
|
+static int wil_fw_process(struct wil6210_priv *wil, const void *data,
|
|
|
+ size_t size, bool load)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
const struct wil_fw_record_head *hdr;
|
|
@@ -437,7 +473,7 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
|
|
|
- &hdr[1], hdr_sz);
|
|
|
+ &hdr[1], hdr_sz, load);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
}
|
|
@@ -456,13 +492,16 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * wil_request_firmware - Request firmware and load to device
|
|
|
+ * wil_request_firmware - Request firmware
|
|
|
*
|
|
|
- * Request firmware image from the file and load it to device
|
|
|
+ * Request firmware image from the file
|
|
|
+ * If load is true, load firmware to device, otherwise
|
|
|
+ * only parse and extract capabilities
|
|
|
*
|
|
|
* Return error code
|
|
|
*/
|
|
|
-int wil_request_firmware(struct wil6210_priv *wil, const char *name)
|
|
|
+int wil_request_firmware(struct wil6210_priv *wil, const char *name,
|
|
|
+ bool load)
|
|
|
{
|
|
|
int rc, rc1;
|
|
|
const struct firmware *fw;
|
|
@@ -482,7 +521,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name)
|
|
|
rc = rc1;
|
|
|
goto out;
|
|
|
}
|
|
|
- rc = wil_fw_load(wil, d, rc1);
|
|
|
+ rc = wil_fw_process(wil, d, rc1, load);
|
|
|
if (rc < 0)
|
|
|
goto out;
|
|
|
}
|