2013-12-14 02:33:25

by Bing Zhao

[permalink] [raw]
Subject: [PATCH 1/4] mwifiex: send regulatory domain info to firmware only if alpha2 changed

On cfg80211 regulatory domain change, drivers gets alpha2 country
code or "00" in driver's notification handler.

In most cases, the pattern will be US, 00, US, 00, US, 00, US, ...
There is no need to send domain info to firmware in case of "00" or
with the same alpha2 country code.

Signed-off-by: Bing Zhao <[email protected]>
---
drivers/net/wireless/mwifiex/cfg80211.c | 19 +++++++++++++------
drivers/net/wireless/mwifiex/sta_ioctl.c | 8 ++++++++
2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index b2f271e..611fbcf 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -542,19 +542,26 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
request->alpha2[0], request->alpha2[1]);

- memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
-
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
case NL80211_REGDOM_SET_BY_CORE:
case NL80211_REGDOM_SET_BY_USER:
- break;
- /* Todo: apply driver specific changes in channel flags based
- on the request initiator if necessary. */
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
break;
+ default:
+ wiphy_err(wiphy, "unknown regdom initiator: %d\n",
+ request->initiator);
+ return;
+ }
+
+ /* Don't send world or same regdom info to firmware */
+ if (strncmp(request->alpha2, "00", 2) &&
+ strncmp(request->alpha2, adapter->country_code,
+ sizeof(request->alpha2))) {
+ memcpy(adapter->country_code, request->alpha2,
+ sizeof(request->alpha2));
+ mwifiex_send_domain_info_cmd_fw(wiphy);
}
- mwifiex_send_domain_info_cmd_fw(wiphy);
}

/*
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 1c67dfe..3259e00 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -205,6 +205,14 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
return 0;
}

+ if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
+ rcu_read_unlock();
+ wiphy_dbg(priv->wdev->wiphy,
+ "11D: skip setting domain info in FW\n");
+ return 0;
+ }
+ memcpy(priv->adapter->country_code, &country_ie[2], 2);
+
domain_info->country_code[0] = country_ie[2];
domain_info->country_code[1] = country_ie[3];
domain_info->country_code[2] = ' ';
--
1.8.2.3



2013-12-14 02:33:34

by Bing Zhao

[permalink] [raw]
Subject: [PATCH 3/4] mwifiex: download cal-data from device-tree to firmware

Currently only conf file based cal-data downloading is supported.
On embedded platforms a better place to store the cal-data is in
device tree. Add cal-data downloading from device tree to firmware.
Both methods can co-exist.

Signed-off-by: Bing Zhao <[email protected]>
---
drivers/net/wireless/mwifiex/main.h | 2 ++
drivers/net/wireless/mwifiex/sta_cmd.c | 61 +++++++++++++++++++++++++++++++---
2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index dc34457..2f50354 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -32,6 +32,7 @@
#include <net/lib80211.h>
#include <linux/firmware.h>
#include <linux/ctype.h>
+#include <linux/of.h>

#include "decl.h"
#include "ioctl.h"
@@ -739,6 +740,7 @@ struct mwifiex_adapter {
u8 scan_delay_cnt;
u8 empty_tx_q_cnt;
const struct firmware *cal_data;
+ struct device_node *dt_node;

/* 11AC */
u32 is_hw_11ac_capable;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 2368c7f..6a95086 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1156,19 +1156,58 @@ static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
return d - dst;
}

+static int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
+ struct device_node *node, const char *prefix)
+{
+#ifdef CONFIG_OF
+ struct property *prop;
+ size_t len = strlen(prefix);
+ int ret;
+
+ /* look for all matching property names */
+ for_each_property_of_node(node, prop) {
+ if (len > strlen(prop->name) ||
+ strncmp(prop->name, prefix, len))
+ continue;
+
+ /* property header is 6 bytes */
+ if (prop && prop->value && prop->length > 6) {
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
+ HostCmd_ACT_GEN_SET, 0,
+ prop);
+ if (ret)
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
/* This function prepares command of set_cfg_data. */
static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
- struct host_cmd_ds_command *cmd)
+ struct host_cmd_ds_command *cmd, void *data_buf)
{
struct mwifiex_adapter *adapter = priv->adapter;
+ struct property *prop = data_buf;
u32 len;
u8 *data = (u8 *)cmd + S_DS_GEN;
+ int ret;

- if ((adapter->cal_data->data) && (adapter->cal_data->size > 0))
+ if (prop) {
+ len = prop->length;
+ ret = of_property_read_u8_array(adapter->dt_node, prop->name,
+ data, len);
+ if (ret)
+ return ret;
+ dev_dbg(adapter->dev,
+ "download cfg_data from device tree: %s\n", prop->name);
+ } else if (adapter->cal_data->data && adapter->cal_data->size > 0) {
len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
adapter->cal_data->size, data);
- else
+ dev_dbg(adapter->dev, "download cfg_data from config file\n");
+ } else {
return -1;
+ }

cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
cmd->size = cpu_to_le16(S_DS_GEN + len);
@@ -1259,7 +1298,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
break;
case HostCmd_CMD_CFG_DATA:
- ret = mwifiex_cmd_cfg_data(priv, cmd_ptr);
+ ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, data_buf);
break;
case HostCmd_CMD_MAC_CONTROL:
ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
@@ -1519,7 +1558,19 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;

- /* Download calibration data to firmware */
+ /* Download calibration data to firmware.
+ * The cal-data can be read from device tree and/or
+ * a configuration file and downloaded to firmware.
+ */
+ adapter->dt_node =
+ of_find_node_by_name(NULL, "marvell_cfgdata");
+ if (adapter->dt_node) {
+ ret = mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
+ "marvell,caldata");
+ if (ret)
+ return -1;
+ }
+
if (adapter->cal_data) {
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
HostCmd_ACT_GEN_SET, 0, NULL);
--
1.8.2.3


2013-12-14 02:33:29

by Bing Zhao

[permalink] [raw]
Subject: [PATCH 4/4] mwifiex: download per country tx power table to firmware

When driver gets regulatory domain change notifications or before
associates to an AP with Country IE, the txpwrlimit table stored
in device tree for that country is downloaded to firmware.

The txpwrlimit downloading will happen only at the first time
when the alpha2 country code is changed. World regulatory domain
"00" notification doesn't trigger the downloading. This behavior
is same as domain_info command.

Signed-off-by: Bing Zhao <[email protected]>
---
drivers/net/wireless/mwifiex/cfg80211.c | 10 ++++++++++
drivers/net/wireless/mwifiex/main.h | 2 ++
drivers/net/wireless/mwifiex/sta_cmd.c | 4 ++--
drivers/net/wireless/mwifiex/sta_ioctl.c | 7 +++++++
4 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 611fbcf..0a10500 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -538,6 +538,8 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_private *priv = mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY);

wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
request->alpha2[0], request->alpha2[1]);
@@ -561,6 +563,14 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
memcpy(adapter->country_code, request->alpha2,
sizeof(request->alpha2));
mwifiex_send_domain_info_cmd_fw(wiphy);
+
+ if (adapter->dt_node) {
+ char txpwr[] = {"marvell,00_txpwrlimit"};
+
+ memcpy(&txpwr[8], adapter->country_code, 2);
+ mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
+ txpwr);
+ }
}
}

diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 2f50354..ab34164 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -1153,6 +1153,8 @@ void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
struct mwifiex_bssdescriptor *bss_desc);
int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
+int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
+ struct device_node *node, const char *prefix);

extern const struct ethtool_ops mwifiex_ethtool_ops;

diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 6a95086..9c2404c 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1156,8 +1156,8 @@ static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)
return d - dst;
}

-static int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
- struct device_node *node, const char *prefix)
+int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
+ struct device_node *node, const char *prefix)
{
#ifdef CONFIG_OF
struct property *prop;
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 3259e00..874ecec 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -234,6 +234,13 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
return -1;
}

+ if (priv->adapter->dt_node) {
+ char txpwr[] = {"marvell,00_txpwrlimit"};
+
+ memcpy(&txpwr[8], priv->adapter->country_code, 2);
+ mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
+ }
+
return 0;
}

--
1.8.2.3


2013-12-14 02:33:41

by Bing Zhao

[permalink] [raw]
Subject: [PATCH 2/4] mwifiex: remove cfg_data construction

The cfg_data buffer will include the cfg_data structure header
(action, type, data_len). This makes it work for all data types
without extra parsing.

Signed-off-by: Bing Zhao <[email protected]>
---
drivers/net/wireless/mwifiex/fw.h | 9 ---------
drivers/net/wireless/mwifiex/sta_cmd.c | 20 ++++++--------------
2 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 8fcb500..4cee6ce 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -468,8 +468,6 @@ enum P2P_MODES {
#define MWIFIEX_CRITERIA_UNICAST BIT(1)
#define MWIFIEX_CRITERIA_MULTICAST BIT(3)

-#define CFG_DATA_TYPE_CAL 2
-
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -1592,12 +1590,6 @@ struct mwifiex_ie_list {
struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
} __packed;

-struct host_cmd_ds_802_11_cfg_data {
- __le16 action;
- __le16 type;
- __le16 data_len;
-} __packed;
-
struct coalesce_filt_field_param {
u8 operation;
u8 operand_len;
@@ -1678,7 +1670,6 @@ struct host_cmd_ds_command {
struct host_cmd_ds_sys_config uap_sys_config;
struct host_cmd_ds_sta_deauth sta_deauth;
struct host_cmd_11ac_vht_cfg vht_cfg;
- struct host_cmd_ds_802_11_cfg_data cfg_data;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 1efa43e..2368c7f 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -1158,28 +1158,20 @@ static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst)

/* This function prepares command of set_cfg_data. */
static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv,
- struct host_cmd_ds_command *cmd,
- u16 cmd_action)
+ struct host_cmd_ds_command *cmd)
{
- struct host_cmd_ds_802_11_cfg_data *cfg_data = &cmd->params.cfg_data;
struct mwifiex_adapter *adapter = priv->adapter;
- u32 len, cal_data_offset;
- u8 *tmp_cmd = (u8 *)cmd;
+ u32 len;
+ u8 *data = (u8 *)cmd + S_DS_GEN;

- cal_data_offset = S_DS_GEN + sizeof(*cfg_data);
if ((adapter->cal_data->data) && (adapter->cal_data->size > 0))
len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data,
- adapter->cal_data->size,
- (u8 *)(tmp_cmd + cal_data_offset));
+ adapter->cal_data->size, data);
else
return -1;

- cfg_data->action = cpu_to_le16(cmd_action);
- cfg_data->type = cpu_to_le16(CFG_DATA_TYPE_CAL);
- cfg_data->data_len = cpu_to_le16(len);
-
cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA);
- cmd->size = cpu_to_le16(S_DS_GEN + sizeof(*cfg_data) + len);
+ cmd->size = cpu_to_le16(S_DS_GEN + len);

return 0;
}
@@ -1267,7 +1259,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
break;
case HostCmd_CMD_CFG_DATA:
- ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, cmd_action);
+ ret = mwifiex_cmd_cfg_data(priv, cmd_ptr);
break;
case HostCmd_CMD_MAC_CONTROL:
ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
--
1.8.2.3