Commit 12bace75 authored by Lior David's avatar Lior David Committed by Kalle Valo

wil6210: extract firmware capabilities from FW file

When driver is loaded, extract a capabilities record
from the FW file. This record contains bits indicating
which optional features are supported by this FW.
The driver can use this information to determine
which functionality to support and/or expose to user
space.
The extraction is done before wiphy structure is
registered, because the capabilities can affect
information published by the this structure.
Signed-off-by: default avatarLior David <qca_liord@qca.qualcomm.com>
Signed-off-by: default avatarMaya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 08989f96
...@@ -1553,6 +1553,30 @@ static const struct file_operations fops_led_blink_time = { ...@@ -1553,6 +1553,30 @@ static const struct file_operations fops_led_blink_time = {
.open = simple_open, .open = simple_open,
}; };
/*---------FW capabilities------------*/
static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX,
wil->fw_capabilities);
return 0;
}
static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, wil_fw_capabilities_debugfs_show,
inode->i_private);
}
static const struct file_operations fops_fw_capabilities = {
.open = wil_fw_capabilities_seq_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
/*----------------*/ /*----------------*/
static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
struct dentry *dbg) struct dentry *dbg)
...@@ -1603,6 +1627,7 @@ static const struct { ...@@ -1603,6 +1627,7 @@ static const struct {
{"recovery", S_IRUGO | S_IWUSR, &fops_recovery}, {"recovery", S_IRUGO | S_IWUSR, &fops_recovery},
{"led_cfg", S_IRUGO | S_IWUSR, &fops_led_cfg}, {"led_cfg", S_IRUGO | S_IWUSR, &fops_led_cfg},
{"led_blink_time", S_IRUGO | S_IWUSR, &fops_led_blink_time}, {"led_blink_time", S_IRUGO | S_IWUSR, &fops_led_blink_time},
{"fw_capabilities", S_IRUGO, &fops_fw_capabilities},
}; };
static void wil6210_debugfs_init_files(struct wil6210_priv *wil, static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
......
/* /*
* Copyright (c) 2014 Qualcomm Atheros, Inc. * Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -58,6 +58,15 @@ struct wil_fw_record_comment { /* type == wil_fw_type_comment */ ...@@ -58,6 +58,15 @@ struct wil_fw_record_comment { /* type == wil_fw_type_comment */
u8 data[0]; /* free-form data [data_size], see above */ u8 data[0]; /* free-form data [data_size], see above */
} __packed; } __packed;
/* FW capabilities encoded inside a comment record */
#define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba)
struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
/* identifies capabilities record */
__le32 magic;
/* capabilities (variable size), see enum wmi_fw_capability */
u8 capabilities[0];
};
/* perform action /* perform action
* data_size = @head.size - offsetof(struct wil_fw_record_action, data) * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
*/ */
......
/* /*
* 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) ...@@ -118,6 +118,12 @@ static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
return (int)dlen; 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, static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
size_t size) size_t size)
{ {
...@@ -126,6 +132,27 @@ static int fw_handle_comment(struct wil6210_priv *wil, const void *data, ...@@ -126,6 +132,27 @@ static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
return 0; 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, static int fw_handle_data(struct wil6210_priv *wil, const void *data,
size_t size) size_t size)
{ {
...@@ -383,42 +410,51 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, ...@@ -383,42 +410,51 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
static const struct { static const struct {
int type; 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_handlers[] = {
{wil_fw_type_comment, fw_handle_comment}, {wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
{wil_fw_type_data, fw_handle_data}, {wil_fw_type_data, fw_handle_data, fw_ignore_section},
{wil_fw_type_fill, fw_handle_fill}, {wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
/* wil_fw_type_action */ /* wil_fw_type_action */
/* wil_fw_type_verify */ /* wil_fw_type_verify */
{wil_fw_type_file_header, fw_handle_file_header}, {wil_fw_type_file_header, fw_handle_file_header,
{wil_fw_type_direct_write, fw_handle_direct_write}, fw_handle_file_header},
{wil_fw_type_gateway_data, fw_handle_gateway_data}, {wil_fw_type_direct_write, fw_handle_direct_write, fw_ignore_section},
{wil_fw_type_gateway_data4, fw_handle_gateway_data4}, {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, 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; 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) 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); wil_err_fw(wil, "unknown record type: %d\n", type);
return -EINVAL; return -EINVAL;
} }
/** /**
* wil_fw_load - load FW into device * wil_fw_process - process section from FW file
* * if load is true: Load the FW and uCode code and data to the
* Load the FW and uCode code and data to the corresponding device * corresponding device memory regions,
* memory regions * otherwise only parse and look for capabilities
* *
* Return error code * 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; int rc = 0;
const struct wil_fw_record_head *hdr; 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) ...@@ -437,7 +473,7 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
return -EINVAL; return -EINVAL;
} }
rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type), rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
&hdr[1], hdr_sz); &hdr[1], hdr_sz, load);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -456,13 +492,16 @@ static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size) ...@@ -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 * 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; int rc, rc1;
const struct firmware *fw; const struct firmware *fw;
...@@ -482,7 +521,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name) ...@@ -482,7 +521,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name)
rc = rc1; rc = rc1;
goto out; goto out;
} }
rc = wil_fw_load(wil, d, rc1); rc = wil_fw_process(wil, d, rc1, load);
if (rc < 0) if (rc < 0)
goto out; goto out;
} }
......
...@@ -894,10 +894,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -894,10 +894,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_halt_cpu(wil); wil_halt_cpu(wil);
/* Loading f/w from the file */ /* Loading f/w from the file */
rc = wil_request_firmware(wil, WIL_FW_NAME); rc = wil_request_firmware(wil, WIL_FW_NAME, true);
if (rc) if (rc)
return rc; return rc;
rc = wil_request_firmware(wil, WIL_FW2_NAME); rc = wil_request_firmware(wil, WIL_FW2_NAME, true);
if (rc) if (rc)
return rc; return rc;
......
...@@ -39,6 +39,7 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -39,6 +39,7 @@ void wil_set_capabilities(struct wil6210_priv *wil)
u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->hw_capabilities, hw_capability_last);
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
switch (rev_id) { switch (rev_id) {
case JTAG_DEV_ID_SPARROW_B0: case JTAG_DEV_ID_SPARROW_B0:
...@@ -52,6 +53,9 @@ void wil_set_capabilities(struct wil6210_priv *wil) ...@@ -52,6 +53,9 @@ void wil_set_capabilities(struct wil6210_priv *wil)
} }
wil_info(wil, "Board hardware is %s\n", wil->hw_name); wil_info(wil, "Board hardware is %s\n", wil->hw_name);
/* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, WIL_FW_NAME, false);
} }
void wil_disable_irq(struct wil6210_priv *wil) void wil_disable_irq(struct wil6210_priv *wil)
......
...@@ -580,6 +580,7 @@ struct wil6210_priv { ...@@ -580,6 +580,7 @@ struct wil6210_priv {
u32 hw_version; u32 hw_version;
const char *hw_name; const char *hw_name;
DECLARE_BITMAP(hw_capabilities, hw_capability_last); DECLARE_BITMAP(hw_capabilities, hw_capability_last);
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
u8 n_mids; /* number of additional MIDs as reported by FW */ u8 n_mids; /* number of additional MIDs as reported by FW */
u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_count; /* num of FW recovery attempts in a short time */
u32 recovery_state; /* FW recovery state machine */ u32 recovery_state; /* FW recovery state machine */
...@@ -895,7 +896,8 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil); ...@@ -895,7 +896,8 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_iftype_nl2wmi(enum nl80211_iftype type);
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
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 wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime); int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment