Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72539799 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by Kalle Valo
Browse files

mwifiex: add custom regulatory domain support



This patch creates custom regulatory rules based on the information
received from firmware and enable them during wiphy registration.

Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 41960b4d
Loading
Loading
Loading
Loading
+25 −14
Original line number Diff line number Diff line
@@ -4141,9 +4141,12 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
	wiphy->cipher_suites = mwifiex_cipher_suites;
	wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);

	if (adapter->region_code)
		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
	if (adapter->regd) {
		wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
					   REGULATORY_DISABLE_BEACON_HINTS |
					   REGULATORY_COUNTRY_IE_IGNORE;
		wiphy_apply_custom_regulatory(wiphy, adapter->regd);
	}

	ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
@@ -4209,19 +4212,27 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
		return ret;
	}

	if (!adapter->regd) {
		if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
			mwifiex_dbg(adapter, INFO,
				    "driver hint alpha2: %2.2s\n", reg_alpha2);
			regulatory_hint(wiphy, reg_alpha2);
		} else {
			if (adapter->region_code == 0x00) {
			mwifiex_dbg(adapter, WARN, "Ignore world regulatory domain\n");
				mwifiex_dbg(adapter, WARN,
					    "Ignore world regulatory domain\n");
			} else {
				wiphy->regulatory_flags |=
					REGULATORY_DISABLE_BEACON_HINTS |
					REGULATORY_COUNTRY_IE_IGNORE;
				country_code =
				mwifiex_11d_code_2_region(adapter->region_code);
					mwifiex_11d_code_2_region(
						adapter->region_code);
				if (country_code &&
				    regulatory_hint(wiphy, country_code))
				mwifiex_dbg(priv->adapter, ERROR, "regulatory_hint() failed\n");
					mwifiex_dbg(priv->adapter, ERROR,
						    "regulatory_hint() failed\n");
			}
		}
	}

+8 −0
Original line number Diff line number Diff line
@@ -416,6 +416,14 @@ enum P2P_MODES {
	P2P_MODE_CLIENT = 3,
};

enum mwifiex_channel_flags {
	MWIFIEX_CHANNEL_PASSIVE = BIT(0),
	MWIFIEX_CHANNEL_DFS = BIT(1),
	MWIFIEX_CHANNEL_NOHT40 = BIT(2),
	MWIFIEX_CHANNEL_NOHT80 = BIT(3),
	MWIFIEX_CHANNEL_DISABLED = BIT(7),
};

#define HostCmd_RET_BIT                       0x8000
#define HostCmd_ACT_GEN_GET                   0x0000
#define HostCmd_ACT_GEN_SET                   0x0001
+2 −0
Original line number Diff line number Diff line
@@ -139,6 +139,8 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
		adapter->nd_info = NULL;
	}

	kfree(adapter->regd);

	vfree(adapter->chan_stats);
	kfree(adapter);
	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -1005,6 +1005,7 @@ struct mwifiex_adapter {
	bool usb_mc_status;
	bool usb_mc_setup;
	struct cfg80211_wowlan_nd_info *nd_info;
	struct ieee80211_regdomain *regd;
};

void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
+91 −0
Original line number Diff line number Diff line
@@ -1022,6 +1022,93 @@ static int mwifiex_ret_robust_coex(struct mwifiex_private *priv,
	return 0;
}

static struct ieee80211_regdomain *
mwifiex_create_custom_regdomain(struct mwifiex_private *priv,
				u8 *buf, u16 buf_len)
{
	u16 num_chan = buf_len / 2;
	struct ieee80211_regdomain *regd;
	struct ieee80211_reg_rule *rule;
	bool new_rule;
	int regd_size, idx, freq, prev_freq = 0;
	u32 bw, prev_bw = 0;
	u8 chflags, prev_chflags = 0, valid_rules = 0;

	if (WARN_ON_ONCE(num_chan > NL80211_MAX_SUPP_REG_RULES))
		return ERR_PTR(-EINVAL);

	regd_size = sizeof(struct ieee80211_regdomain) +
		    num_chan * sizeof(struct ieee80211_reg_rule);

	regd = kzalloc(regd_size, GFP_KERNEL);
	if (!regd)
		return ERR_PTR(-ENOMEM);

	for (idx = 0; idx < num_chan; idx++) {
		u8 chan;
		enum nl80211_band band;

		chan = *buf++;
		if (!chan)
			return NULL;
		chflags = *buf++;
		band = (chan <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
		freq = ieee80211_channel_to_frequency(chan, band);
		new_rule = false;

		if (chflags & MWIFIEX_CHANNEL_DISABLED)
			continue;

		if (band == NL80211_BAND_5GHZ) {
			if (!(chflags & MWIFIEX_CHANNEL_NOHT80))
				bw = MHZ_TO_KHZ(80);
			else if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
				bw = MHZ_TO_KHZ(40);
			else
				bw = MHZ_TO_KHZ(20);
		} else {
			if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
				bw = MHZ_TO_KHZ(40);
			else
				bw = MHZ_TO_KHZ(20);
		}

		if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
		    freq - prev_freq > 20) {
			valid_rules++;
			new_rule = true;
		}

		rule = &regd->reg_rules[valid_rules - 1];

		rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);

		prev_chflags = chflags;
		prev_freq = freq;
		prev_bw = bw;

		if (!new_rule)
			continue;

		rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
		rule->power_rule.max_eirp = DBM_TO_MBM(19);

		if (chflags & MWIFIEX_CHANNEL_PASSIVE)
			rule->flags = NL80211_RRF_NO_IR;

		if (chflags & MWIFIEX_CHANNEL_DFS)
			rule->flags = NL80211_RRF_DFS;

		rule->freq_range.max_bandwidth_khz = bw;
	}

	regd->n_reg_rules = valid_rules;
	regd->alpha2[0] = '9';
	regd->alpha2[1] = '9';

	return regd;
}

static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
				       struct host_cmd_ds_command *resp)
{
@@ -1050,6 +1137,10 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
			mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:",
					 (u8 *)head + sizeof(*head),
					 tlv_buf_len);
			priv->adapter->regd =
				mwifiex_create_custom_regdomain(priv,
								(u8 *)head +
						sizeof(*head), tlv_buf_len);
			break;
		}