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

Commit 6b70e7eb authored by Victor Goldenshtein's avatar Victor Goldenshtein Committed by Luciano Coelho
Browse files

wlcore: add new reg-domain configuration command



In 18xx the calibration process of the PHY Cortex domain
requires to perform an active calibration of the channel
before it can be used for transmission. To fulfill world
wide regulatory restrictions, fw should be always
synchronized/updated with current CRDA configuration.
Add a new "CMD_DFS_CHANNEL_CONFIG" command to update the
fw with current reg-domain, this command passes a bit map
of channels that are allowed to be used for transmission.

The driver shall update the fw during initialization and
after each change in the current reg-domain
configuration. The driver will save the channel number of
incoming beacons during the scan process, as they might
be a result of the passive scan on
"IEEE80211_CHAN_PASSIVE_SCAN" channel and will update the
fw accordingly once the scan is finished, the purpose of
this is to be ready in case of the authentication request
on one of these disabled (uncalibrated) channels.

The new command requires to wait for the fw completion
event "DFS_CHANNELS_CONFIG_COMPLETE_EVENT".

No scan commands (including the sched scan) can be
executed concurrently with the "CMD_DFS_CHANNEL_CONFIG",
wl->mutex ensures that.

[Arik - move reset of reg_ch_conf_last to safe place inside
op_stop_locked]
[Eliad - adjust to new event waiting api]

Signed-off-by: default avatarVictor Goldenshtein <victorg@ti.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarEliad Peller <eliad@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 978cd3a0
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -34,6 +34,10 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
		local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
		break;

	case WLCORE_EVENT_DFS_CONFIG_COMPLETE:
		local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
		break;

	default:
		/* event not implemented */
		return 0;
+3 −1
Original line number Diff line number Diff line
@@ -616,6 +616,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
			      WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
			      WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
			      WLCORE_QUIRK_TX_PAD_LAST_FRAME |
			      WLCORE_QUIRK_REGDOMAIN_CONF |
			      WLCORE_QUIRK_DUAL_PROBE_TMPL;

		wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER,
@@ -862,7 +863,8 @@ static int wl18xx_boot(struct wl1271 *wl)
		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
		INACTIVE_STA_EVENT_ID |
		MAX_TX_FAILURE_EVENT_ID |
		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
		CHANNEL_SWITCH_COMPLETE_EVENT_ID |
		DFS_CHANNELS_CONFIG_COMPLETE_EVENT;

	ret = wlcore_boot_run_firmware(wl);
	if (ret < 0)
+125 −0
Original line number Diff line number Diff line
@@ -1503,6 +1503,131 @@ out:
	return ret;
}

static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)
{
	int idx = -1;

	switch (band) {
	case IEEE80211_BAND_5GHZ:
		if (ch >= 8 && ch <= 16)
			idx = ((ch-8)/4 + 18);
		else if (ch >= 34 && ch <= 64)
			idx = ((ch-34)/2 + 3 + 18);
		else if (ch >= 100 && ch <= 140)
			idx = ((ch-100)/4 + 15 + 18);
		else if (ch >= 149 && ch <= 165)
			idx = ((ch-149)/4 + 26 + 18);
		else
			idx = -1;
		break;
	case IEEE80211_BAND_2GHZ:
		if (ch >= 1 && ch <= 14)
			idx = ch - 1;
		else
			idx = -1;
		break;
	default:
		wl1271_error("get reg conf ch idx - unknown band: %d",
			     (int)band);
	}

	return idx;
}

void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
				     enum ieee80211_band band)
{
	int ch_bit_idx = 0;

	if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
		return;

	ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel);

	if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
		set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);
}

int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
{
	struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL;
	int ret = 0, i, b, ch_bit_idx;
	struct ieee80211_channel *channel;
	u32 tmp_ch_bitmap[2];
	u16 ch;
	struct wiphy *wiphy = wl->hw->wiphy;
	struct ieee80211_supported_band *band;
	bool timeout = false;

	if (!(wl->quirks & WLCORE_QUIRK_REGDOMAIN_CONF))
		return 0;

	wl1271_debug(DEBUG_CMD, "cmd reg domain config");

	memset(tmp_ch_bitmap, 0, sizeof(tmp_ch_bitmap));

	for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) {
		band = wiphy->bands[b];
		for (i = 0; i < band->n_channels; i++) {
			channel = &band->channels[i];
			ch = channel->hw_value;

			if (channel->flags & (IEEE80211_CHAN_DISABLED |
					      IEEE80211_CHAN_RADAR |
					      IEEE80211_CHAN_PASSIVE_SCAN))
				continue;

			ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
			if (ch_bit_idx < 0)
				continue;

			set_bit(ch_bit_idx, (long *)tmp_ch_bitmap);
		}
	}

	tmp_ch_bitmap[0] |= wl->reg_ch_conf_pending[0];
	tmp_ch_bitmap[1] |= wl->reg_ch_conf_pending[1];

	if (!memcmp(tmp_ch_bitmap, wl->reg_ch_conf_last, sizeof(tmp_ch_bitmap)))
		goto out;

	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
	if (!cmd) {
		ret = -ENOMEM;
		goto out;
	}

	cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]);
	cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]);

	wl1271_debug(DEBUG_CMD,
		     "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x",
		     cmd->ch_bit_map1, cmd->ch_bit_map2);

	ret = wl1271_cmd_send(wl, CMD_DFS_CHANNEL_CONFIG, cmd, sizeof(*cmd), 0);
	if (ret < 0) {
		wl1271_error("failed to send reg domain dfs config");
		goto out;
	}

	ret = wl->ops->wait_for_event(wl,
				      WLCORE_EVENT_DFS_CONFIG_COMPLETE,
				      &timeout);
	if (ret < 0 || timeout) {
		wl1271_error("reg domain conf %serror",
			     timeout ? "completion " : "");
		ret = timeout ? -ETIMEDOUT : ret;
		goto out;
	}

	memcpy(wl->reg_ch_conf_last, tmp_ch_bitmap, sizeof(tmp_ch_bitmap));
	memset(wl->reg_ch_conf_pending, 0, sizeof(wl->reg_ch_conf_pending));

out:
	kfree(cmd);
	return ret;
}

int wl12xx_cmd_config_fwlog(struct wl1271 *wl)
{
	struct wl12xx_cmd_config_fwlog *cmd;
+10 −0
Original line number Diff line number Diff line
@@ -84,6 +84,9 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id);
int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
			struct ieee80211_sta *sta, u8 hlid);
int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
				     enum ieee80211_band band);
int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
@@ -623,6 +626,13 @@ enum wl12xx_fwlogger_output {
	WL12XX_FWLOG_OUTPUT_HOST,
};

struct wl12xx_cmd_regdomain_dfs_config {
	struct wl1271_cmd_header header;

	__le32 ch_bit_map1;
	__le32 ch_bit_map2;
} __packed;

struct wl12xx_cmd_config_fwlog {
	struct wl1271_cmd_header header;

+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ enum {
enum wlcore_wait_event {
	WLCORE_EVENT_ROLE_STOP_COMPLETE,
	WLCORE_EVENT_PEER_REMOVE_COMPLETE,
	WLCORE_EVENT_DFS_CONFIG_COMPLETE
};

enum {
Loading