2020-08-27 23:31:53

by Ben Greear

[permalink] [raw]
Subject: [PATCH 1/2] ath11k: Support reading fwcfg file for driver options.

From: Ben Greear <[email protected]>

The QCA6390 NIC that I have randomizes the last two octets
each time the module loads. So, introduce a 'fwcfg' option
so that we can specify a MAC for each radio. This fwcfg
file will also let one specify the board file name.

Example fwcfg file:

mac = 00:03:7f:00:00:01

Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath11k/core.c | 161 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/core.h | 9 ++
drivers/net/wireless/ath/ath11k/wmi.c | 12 +-
3 files changed, 178 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 55de538aa785..3166b9a9f896 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/remoteproc.h>
#include <linux/firmware.h>
+#include <linux/ctype.h>
#include "core.h"
#include "dp_tx.h"
#include "dp_rx.h"
@@ -233,6 +234,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,
int ret, ie_id;

filename = ATH11K_BOARD_API2_FILE;
+ if (ab->fwcfg.bname[0])
+ filename = ab->fwcfg.bname;

if (!bd->fw)
bd->fw = ath11k_core_firmware_request(ab, filename);
@@ -310,6 +313,7 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,
data += ie_len;
}

+ strlcpy(ab->fw_board_name, filename, sizeof(ab->fw_board_name));
out:
if (!bd->data || !bd->len) {
ath11k_err(ab,
@@ -326,16 +330,160 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,
return ret;
}

+static int ath11k_fetch_fwcfg_file(struct ath11k_base *ab)
+{
+ char filename[100];
+ const char *buf;
+ size_t i = 0;
+ char val[100];
+ size_t key_idx;
+ size_t val_idx;
+ char c;
+ size_t sz;
+ int ret;
+ const struct firmware *fw;
+
+ ab->fwcfg.flags = 0;
+
+ /* fwcfg-<bus>-<id>.txt */
+ /* If this changes, change ath11k_read_fwinfo as well. */
+ scnprintf(filename, sizeof(filename), "%s/fwcfg-%s-%s.txt",
+ ATH11K_FW_DIR, ath11k_bus_str(ab->hif.bus), dev_name(ab->dev));
+
+ ret = firmware_request_nowarn(&fw, filename, ab->dev);
+ if (ret)
+ ab->fwcfg_file = ERR_PTR(ret);
+ else
+ ab->fwcfg_file = fw;
+ if (IS_ERR(ab->fwcfg_file)) {
+ /* FW config file is optional, don't be scary. */
+ ath11k_dbg(ab, ATH11K_DBG_BOOT,
+ "Could not find firmware config file %s, continuing with defaults.\n",
+ filename);
+ return PTR_ERR(ab->fwcfg_file);
+ }
+
+ ath11k_dbg(ab, ATH11K_DBG_BOOT, "found firmware config file %s\n",
+ filename);
+
+ /* Now, attempt to parse results.
+ * Format is key=value
+ */
+ buf = (const char *)(ab->fwcfg_file->data);
+ while (i < ab->fwcfg_file->size) {
+start_again:
+ /* First, eat space, or entire line if we have # as first char */
+ c = buf[i];
+ while (isspace(c)) {
+ i++;
+ if (i >= ab->fwcfg_file->size)
+ goto done;
+ c = buf[i];
+ }
+ /* Eat comment ? */
+ if (c == '#') {
+ i++;
+ while (i < ab->fwcfg_file->size) {
+ c = buf[i];
+ i++;
+ if (c == '\n')
+ goto start_again;
+ }
+ /* Found no newline, must be done. */
+ goto done;
+ }
+
+ /* If here, we have start of token, store it in 'filename' to save space */
+ key_idx = 0;
+ while (i < ab->fwcfg_file->size) {
+ c = buf[i];
+ if (c == '=') {
+ i++;
+ c = buf[i];
+ /* Eat any space after the '=' sign. */
+ while (i < ab->fwcfg_file->size) {
+ if (!isspace(c))
+ break;
+ i++;
+ c = buf[i];
+ }
+ break;
+ }
+ if (isspace(c)) {
+ i++;
+ continue;
+ }
+ filename[key_idx] = c;
+ key_idx++;
+ if (key_idx >= sizeof(filename)) {
+ /* Too long, bail out. */
+ goto done;
+ }
+ i++;
+ }
+ filename[key_idx] = 0; /* null terminate */
+
+ /* We have found the key, now find the value */
+ val_idx = 0;
+ while (i < ab->fwcfg_file->size) {
+ c = buf[i];
+ if (isspace(c))
+ break;
+ val[val_idx] = c;
+ val_idx++;
+ if (val_idx >= sizeof(val)) {
+ /* Too long, bail out. */
+ goto done;
+ }
+ i++;
+ }
+ val[val_idx] = 0; /* null terminate value */
+
+ /* We have key and value now. */
+ ath11k_warn(ab, "fwcfg key: %s val: %s\n",
+ filename, val);
+
+ /* Assign key and values as appropriate */
+ if (strcasecmp(filename, "mac") == 0) {
+ if (!mac_pton(val, ab->fwcfg.mac))
+ ath11k_warn(ab, "Failed to parse fwcfg mac address: %s\n",
+ val);
+ else
+ ab->fwcfg.flags |= ATH11K_FWCFG_MAC;
+ } else if (strcasecmp(filename, "bname") == 0) {
+ sz = sizeof(ab->fwcfg.bname);
+ strncpy(ab->fwcfg.bname, val, sz);
+ ab->fwcfg.bname[sz - 1] = 0; /* ensure null term */
+ } else {
+ ath11k_warn(ab, "Unknown fwcfg key name -:%s:-, val: %s\n",
+ filename, val);
+ }
+ }
+done:
+ return 0;
+}
+
static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab,
struct ath11k_board_data *bd)
{
- bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE);
+ if (ab->fwcfg.bname[0])
+ bd->fw = ath11k_core_firmware_request(ab, ab->fwcfg.bname);
+ else
+ bd->fw = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_BOARD_FILE);
if (IS_ERR(bd->fw))
return PTR_ERR(bd->fw);

bd->data = bd->fw->data;
bd->len = bd->fw->size;

+ /* Save firmware board name so we can display it later. */
+ if (ab->fwcfg.bname[0])
+ strlcpy(ab->fw_board_name, ab->fwcfg.bname,
+ sizeof(ab->fw_board_name));
+ else
+ strlcpy(ab->fw_board_name, ATH11K_DEFAULT_BOARD_FILE,
+ sizeof(ab->fw_board_name));
+
return 0;
}

@@ -483,6 +631,13 @@ static int ath11k_core_start(struct ath11k_base *ab,
{
int ret;

+ /* Load optional firmware config from file system */
+ if (!IS_ERR(ab->fwcfg_file)) {
+ release_firmware(ab->fwcfg_file);
+ ab->fwcfg_file = NULL;
+ }
+ ath11k_fetch_fwcfg_file(ab);
+
ret = ath11k_qmi_firmware_start(ab, mode);
if (ret) {
ath11k_err(ab, "failed to attach wmi: %d\n", ret);
@@ -865,6 +1020,10 @@ void ath11k_core_deinit(struct ath11k_base *ab)
ath11k_hif_power_down(ab);
ath11k_mac_destroy(ab);
ath11k_core_soc_destroy(ab);
+
+ if (!IS_ERR(ab->fwcfg_file))
+ release_firmware(ab->fwcfg_file);
+ ab->fwcfg_file = NULL;
}
EXPORT_SYMBOL(ath11k_core_deinit);

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index ef1a934221f0..bb22b41fefaa 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -685,6 +685,15 @@ struct ath11k_base {

const struct firmware *cal_file;

+ const struct firmware *fwcfg_file;
+ char fw_board_name[100]; /* whatever board file we actually loaded */
+ struct {
+#define ATH11K_FWCFG_MAC BIT(0)
+ u32 flags; /* let us know which fields have been set */
+ char bname[100]; /* board file name */
+ u8 mac[ETH_ALEN]; /* MAC address to use */
+ } fwcfg;
+
/* Below regd's are protected by ab->data_lock */
/* This is the regd set for every radio
* by the firmware during initializatin
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 03b669de3300..95f2af6bbdcd 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -5562,11 +5562,17 @@ static int ath11k_wmi_tlv_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
ab->wlan_init_status = fixed_param.ready_event_min.status;
rdy_parse->num_extra_mac_addr =
fixed_param.ready_event_min.num_extra_mac_addr;
-
- ether_addr_copy(ab->mac_addr,
- fixed_param.ready_event_min.mac_addr.addr);
+ if (ab->fwcfg.flags & ATH11K_FWCFG_MAC)
+ ether_addr_copy(ab->mac_addr, ab->fwcfg.mac);
+ else
+ ether_addr_copy(ab->mac_addr,
+ fixed_param.ready_event_min.mac_addr.addr);
ab->pktlog_defs_checksum = fixed_param.pktlog_defs_checksum;
ab->wmi_ready = true;
+ ath11k_warn(ab, "tag-ready-event, using mac: %pM NIC reported: %pM extra-mac: %d status: %d\n",
+ ab->mac_addr,
+ fixed_param.ready_event_min.mac_addr.addr,
+ rdy_parse->num_extra_mac_addr, ab->wlan_init_status);
break;
case WMI_TAG_ARRAY_FIXED_STRUCT:
addr_list = (struct wmi_mac_addr *)ptr;
--
2.26.2


2020-08-27 23:32:15

by Ben Greear

[permalink] [raw]
Subject: [PATCH 2/2] ath11k: Add firmware_info file to debugfs

From: Ben Greear <[email protected]>

This shows the fwcfg file name so that users don't have to guess,
as well as some other info about the firmware and radio.

directory: QCA6390/hw2.0
fwcfg: fwcfg-pci-0000:14:00.0.txt
bus: 0000:14:00.0
version: 0x101c06cc
hw_rev: 6390-hw2
board: board.bin

Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath11k/debug.c | 56 +++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c
index 2ac0df8aee26..38ffcae67ab5 100644
--- a/drivers/net/wireless/ath/ath11k/debug.c
+++ b/drivers/net/wireless/ath/ath11k/debug.c
@@ -398,6 +398,59 @@ static const struct file_operations fops_pdev_stats = {
.llseek = default_llseek,
};

+static ssize_t ath11k_read_fwinfo(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k_base *ab = file->private_data;
+ char *buf;
+ unsigned int len = 0, buf_len = 1000;
+ ssize_t ret_cnt;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* TODO: Locking? */
+
+ len = snprintf(buf, buf_len, "directory: %s\nfwcfg: fwcfg-%s-%s.txt\nbus: %s",
+ ab->hw_params.fw.dir,
+ ath11k_bus_str(ab->hif.bus), dev_name(ab->dev), dev_name(ab->dev));
+
+ /* Just to be safe */
+ buf[buf_len - 1] = 0;
+ len = strlen(buf);
+
+ len += snprintf(buf + len, buf_len - len, "\nversion: 0x%0x\nhw_rev: ",
+ ab->qmi.target.fw_version);
+ switch (ab->hw_rev) {
+ case ATH11K_HW_QCA6390_HW11:
+ len += snprintf(buf + len, buf_len - len, "6390-hw1\n");
+ break;
+ case ATH11K_HW_QCA6390_HW20:
+ len += snprintf(buf + len, buf_len - len, "6390-hw2\n");
+ break;
+ case ATH11K_HW_IPQ8074:
+ len += snprintf(buf + len, buf_len - len, "8074\n");
+ break;
+ }
+
+ len += snprintf(buf + len, buf_len - len, "board: %s\n",
+ ab->fw_board_name);
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+ return ret_cnt;
+}
+
+static const struct file_operations fops_fwinfo_services = {
+ .read = ath11k_read_fwinfo,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
{
struct ath11k *ar = inode->i_private;
@@ -1201,6 +1254,9 @@ int ath11k_debug_register(struct ath11k *ar)
&ar->dfs_block_radar_events);
}

+ debugfs_create_file("firmware_info", 0400, ar->debug.debugfs_pdev, ab,
+ &fops_fwinfo_services);
+
return 0;
}

--
2.26.2

2020-08-28 01:51:27

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 2/2] ath11k: Add firmware_info file to debugfs

Hi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on ath6kl/ath-next]
[also build test ERROR on next-20200827]
[cannot apply to v5.9-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/greearb-candelatech-com/ath11k-Support-reading-fwcfg-file-for-driver-options/20200828-073256
base: https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git ath-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

drivers/net/wireless/ath/ath11k/debug.c: In function 'ath11k_read_fwinfo':
>> drivers/net/wireless/ath/ath11k/debug.c:427:7: error: 'ATH11K_HW_QCA6390_HW11' undeclared (first use in this function); did you mean 'ATH11K_HW_QCA6390_HW20'?
427 | case ATH11K_HW_QCA6390_HW11:
| ^~~~~~~~~~~~~~~~~~~~~~
| ATH11K_HW_QCA6390_HW20
drivers/net/wireless/ath/ath11k/debug.c:427:7: note: each undeclared identifier is reported only once for each function it appears in

# https://github.com/0day-ci/linux/commit/a7df025ce74fb120141d5c66a46febd63b74cb97
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review greearb-candelatech-com/ath11k-Support-reading-fwcfg-file-for-driver-options/20200828-073256
git checkout a7df025ce74fb120141d5c66a46febd63b74cb97
vim +427 drivers/net/wireless/ath/ath11k/debug.c

400
401 static ssize_t ath11k_read_fwinfo(struct file *file,
402 char __user *user_buf,
403 size_t count, loff_t *ppos)
404 {
405 struct ath11k_base *ab = file->private_data;
406 char *buf;
407 unsigned int len = 0, buf_len = 1000;
408 ssize_t ret_cnt;
409
410 buf = kzalloc(buf_len, GFP_KERNEL);
411 if (!buf)
412 return -ENOMEM;
413
414 /* TODO: Locking? */
415
416 len = snprintf(buf, buf_len, "directory: %s\nfwcfg: fwcfg-%s-%s.txt\nbus: %s",
417 ab->hw_params.fw.dir,
418 ath11k_bus_str(ab->hif.bus), dev_name(ab->dev), dev_name(ab->dev));
419
420 /* Just to be safe */
421 buf[buf_len - 1] = 0;
422 len = strlen(buf);
423
424 len += snprintf(buf + len, buf_len - len, "\nversion: 0x%0x\nhw_rev: ",
425 ab->qmi.target.fw_version);
426 switch (ab->hw_rev) {
> 427 case ATH11K_HW_QCA6390_HW11:
428 len += snprintf(buf + len, buf_len - len, "6390-hw1\n");
429 break;
430 case ATH11K_HW_QCA6390_HW20:
431 len += snprintf(buf + len, buf_len - len, "6390-hw2\n");
432 break;
433 case ATH11K_HW_IPQ8074:
434 len += snprintf(buf + len, buf_len - len, "8074\n");
435 break;
436 }
437
438 len += snprintf(buf + len, buf_len - len, "board: %s\n",
439 ab->fw_board_name);
440
441 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
442
443 kfree(buf);
444 return ret_cnt;
445 }
446

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (3.64 kB)
.config.gz (63.79 kB)
Download all attachments