2023-01-23 18:05:47

by carson.vandegriffe

[permalink] [raw]
Subject: [RFC PATCH] wifi: mt76: mt7916: Support per-radio configuration 'firmware' file.

From: Carson Vandegriffe <[email protected]>

This lets users specify the upper band that the 7916 radio should use.
Upon reboot, the 7916 will be using that upper band.

Example config file:

myhost@: cat /usr/lib/firmware/mediatek/fwcfg-mmio-0000\:04\:00.0.txt

high_band=6

Signed-off-by: Carson Vandegriffe <[email protected]>
---
This patch is against the 5.19.17+ kernel.
drivers/net/wireless/mediatek/mt76/mt76.h | 14 ++
.../wireless/mediatek/mt76/mt7915/eeprom.c | 164 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7915/init.c | 3 +-
.../wireless/mediatek/mt76/mt7915/mt7915.h | 10 ++
4 files changed, 190 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 812c1eb8866a..2b1b730aeb2d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -961,6 +961,20 @@ struct mt76_sta_stats {
u32 rx_ampdu_len[15];
};

+static inline const char *mt76_bus_str(enum mt76_bus_type bus)
+{
+ switch (bus) {
+ case MT76_BUS_MMIO:
+ return "mmio";
+ case MT76_BUS_USB:
+ return "usb";
+ case MT76_BUS_SDIO:
+ return "sdio";
+ }
+
+ return "unknown";
+}
+
static inline
void mt76_inc_ampdu_bucket(int ampdu_len, struct mt76_sta_stats *stats)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index fdef6a3a6cb3..04edadcf5107 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -108,6 +108,28 @@ mt7915_eeprom_load_default(struct mt7915_dev *dev)
return ret;
}

+static const struct firmware
+*mt7915_eeprom_load_file(struct mt7915_dev *dev, const char *dir, const char *file)
+{
+ char filename[100];
+ const struct firmware *fw = NULL;
+ int ret;
+
+ if (!file)
+ return ERR_PTR(-ENOENT);
+
+ if (!dir)
+ dir = ".";
+
+ snprintf(filename, sizeof(filename), "%s/%s", dir, file);
+ ret = request_firmware(&fw, filename, dev->mt76.dev);
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ return fw;
+}
+
static int mt7915_eeprom_load(struct mt7915_dev *dev)
{
int ret;
@@ -139,6 +161,122 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
return mt7915_check_eeprom(dev);
}

+static int mt7915_fetch_fwcfg_file(struct mt7915_dev *dev)
+{
+ char filename[100];
+ const struct firmware *fw;
+ const char *buf;
+ size_t i = 0;
+ char val[100];
+ size_t key_idx;
+ size_t val_idx;
+ char c;
+ long t;
+
+ dev->fwcfg.flags = 0;
+
+ /* fwcfg-<bus>-<id>.txt */
+ scnprintf(filename, sizeof(filename), "fwcfg-%s-%s.txt",
+ mt76_bus_str(dev->mt76.bus->type), dev_name(dev->mt76.dev));
+
+ fw = mt7915_eeprom_load_file(dev, MT7915_FIRMWARE_BD, filename);
+ if (IS_ERR(fw))
+ return PTR_ERR(fw);
+
+ /* Now, attempt to parse results.
+ * Format is key=value
+ */
+ buf = (const char *)(fw->data);
+ while (i < fw->size) {
+start_again:
+ /* First, eat space, or entire line if we have # as first char */
+ c = buf[i];
+ while (isspace(c)) {
+ i++;
+ if (i >= fw->size)
+ goto done;
+ c = buf[i];
+ }
+ /* Eat comment ? */
+ if (c == '#') {
+ i++;
+ while (i < fw->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 < fw->size) {
+ c = buf[i];
+ if (c == '=') {
+ i++;
+ c = buf[i];
+ /* Eat any space after the '=' sign. */
+ while (i < fw->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 < fw->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. */
+ dev_warn(dev->mt76.dev, "fwcfg key: %s val: %s\n",
+ filename, val);
+
+ /* Assign key and values as appropriate */
+ if (strcasecmp(filename, "high_band") == 0) {
+ if (kstrtol(val, 0, &t) == 0) {
+ dev->fwcfg.high_band = t;
+ dev->fwcfg.flags |= MT7915_FWCFG_HIGH_BAND;
+ }
+ } else {
+ dev_warn(dev->mt76.dev, "Unknown fwcfg key name -:%s:-, val: %s\n",
+ filename, val);
+ }
+ }
+
+done:
+ release_firmware(fw);
+ return 0;
+}
+
static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
@@ -149,6 +287,29 @@ static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);

if (!is_mt7915(&dev->mt76)) {
+ /* fwcfg intervention to set upper band to 5GHz or 6GHz */
+ if ((dev->fwcfg.flags & MT7915_FWCFG_HIGH_BAND) &&
+ val == MT_EE_V2_BAND_SEL_5GHZ_6GHZ) {
+ dev_info(dev->mt76.dev, "FWCFG: Overriding 7916 high_band with %luGHz\n",
+ (unsigned long)dev->fwcfg.high_band);
+
+ if (dev->fwcfg.high_band == 5) {
+ u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + phy->band_idx],
+ MT_EE_V2_BAND_SEL_5GHZ,
+ MT_EE_WIFI_CONF0_BAND_SEL);
+ }
+ if (dev->fwcfg.high_band == 6) {
+ u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + phy->band_idx],
+ MT_EE_V2_BAND_SEL_6GHZ,
+ MT_EE_WIFI_CONF0_BAND_SEL);
+ }
+
+ /* force to buffer mode */
+ dev->flash_mode = true;
+ val = eeprom[MT_EE_WIFI_CONF + phy->band_idx];
+ val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
+ }
+
switch (val) {
case MT_EE_V2_BAND_SEL_5GHZ:
phy->mt76->cap.has_5ghz = true;
@@ -270,6 +431,9 @@ int mt7915_eeprom_init(struct mt7915_dev *dev)
{
int ret;

+ /* First, see if we have a special config file for this firmware */
+ mt7915_fetch_fwcfg_file(dev);
+
dev->bin_file_mode = mt76_check_bin_file_mode(&dev->mt76);

if (dev->bin_file_mode) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index f82e36664994..2a31b973c843 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -1195,7 +1195,6 @@ int mt7915_register_device(struct mt7915_dev *dev)
if (ret)
goto unreg_dev;

- ieee80211_queue_work(mt76_hw(dev), &dev->init_work);

if (phy2) {
ret = mt7915_register_ext_phy(dev, phy2);
@@ -1203,6 +1202,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
goto unreg_thermal;
}

+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
mt7915_init_debugfs(&dev->phy);

dev->ser.hw_init_done = true;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index dabf9dce7ed6..f8266de129dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -5,6 +5,7 @@
#define __MT7915_H

#include <linux/interrupt.h>
+#include <linux/firmware.h>
#include <linux/ktime.h>
#include "../mt76_connac.h"
#include "regs.h"
@@ -28,6 +29,8 @@
#define MT7915_RX_RING_SIZE 1536
#define MT7915_RX_MCU_RING_SIZE 512

+#define MT7915_FIRMWARE_BD "mediatek"
+
#define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin"
#define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin"
#define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin"
@@ -467,6 +470,13 @@ struct mt7915_dev {
u8 dpd_chan_num_5g;
u8 dpd_chan_num_6g;

+ struct {
+#define MT7915_FWCFG_HIGH_BAND BIT(1)
+
+ u32 flags; /* let us know which fields have been set */
+ u32 high_band; /* sets upper-band to use ('5' or '6')GHz */
+ } fwcfg;
+
struct {
u8 debug_wm;
u8 debug_wa;
--
2.34.1



2023-02-07 15:13:53

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC PATCH] wifi: mt76: mt7916: Support per-radio configuration 'firmware' file.

[email protected] writes:

> From: Carson Vandegriffe <[email protected]>
>
> This lets users specify the upper band that the 7916 radio should use.
> Upon reboot, the 7916 will be using that upper band.
>
> Example config file:
>
> myhost@: cat /usr/lib/firmware/mediatek/fwcfg-mmio-0000\:04\:00.0.txt
>
> high_band=6
>
> Signed-off-by: Carson Vandegriffe <[email protected]>

So this is basically an .ini file with settings for the driver? It's a
long standing request feature request how wireless drivers should handle
thatbut there's still no resolution. Having an ASCII parser in the
driver does not sound a good idea.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-02-07 16:49:22

by Ben Greear

[permalink] [raw]
Subject: Re: [RFC PATCH] wifi: mt76: mt7916: Support per-radio configuration 'firmware' file.

On 2/7/23 07:13, Kalle Valo wrote:
> [email protected] writes:
>
>> From: Carson Vandegriffe <[email protected]>
>>
>> This lets users specify the upper band that the 7916 radio should use.
>> Upon reboot, the 7916 will be using that upper band.
>>
>> Example config file:
>>
>> myhost@: cat /usr/lib/firmware/mediatek/fwcfg-mmio-0000\:04\:00.0.txt
>>
>> high_band=6
>>
>> Signed-off-by: Carson Vandegriffe <[email protected]>
>
> So this is basically an .ini file with settings for the driver? It's a
> long standing request feature request how wireless drivers should handle
> thatbut there's still no resolution. Having an ASCII parser in the
> driver does not sound a good idea.

It has been many years, no one has offered a better solution that I'm
aware of, so....how long to wait?

Perhaps the parsing logic could move to some helper methods higher in the stack and create a table of
key/value pairs to be used by drivers so that multiple drivers could more easily re-use the parsing
code?

Thanks,
Ben

--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com