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

Commit 2610b5c7 authored by Alexei Avshalom Lazar's avatar Alexei Avshalom Lazar
Browse files

wil6210: Add EDMG channel support



Add support for Enhanced Directional Multi-Gigabit (EDMG) channels 9-11.
wil6210 reports it's EDMG capabilities (that are also based on FW
capability) to cfg80211 by filling
wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.
wil6210 handles edmg.channels and edmg.bw_config requested in connect
and start_ap operations.

Change-Id: I96a2776fe27ed2d8e922e23063e879361cfcb552
Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Git-commit: 9abe3e306eccdf23e482b3a6dde178311d592765
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git


[ailizaro@codeaurora.org: trivial conflict fixes]
Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
parent afd697d0
Loading
Loading
Loading
Loading
+122 −9
Original line number Diff line number Diff line
@@ -18,6 +18,22 @@
#define WIL_BRD_SUFFIX_CN "CN"
#define WIL_BRD_SUFFIX_FCC "FCC"

#define WIL_EDMG_CHANNEL_9_SUBCHANNELS	(BIT(0) | BIT(1))
#define WIL_EDMG_CHANNEL_10_SUBCHANNELS	(BIT(1) | BIT(2))
#define WIL_EDMG_CHANNEL_11_SUBCHANNELS	(BIT(2) | BIT(3))

/* WIL_EDMG_BW_CONFIGURATION define the allowed channel bandwidth
 * configurations as defined by IEEE 802.11 section 9.4.2.251, Table 13.
 * The value 5 allowing CB1 and CB2 of adjacent channels.
 */
#define WIL_EDMG_BW_CONFIGURATION 5

/* WIL_EDMG_CHANNELS is a bitmap that indicates the 2.16 GHz channel(s) that
 * are allowed to be used for EDMG transmissions in the BSS as defined by
 * IEEE 802.11 section 9.4.2.251.
 */
#define WIL_EDMG_CHANNELS (BIT(0) | BIT(1) | BIT(2) | BIT(3))

bool disable_ap_sme;
module_param(disable_ap_sme, bool, 0444);
MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
@@ -56,6 +72,39 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
	CHAN60G(4, 0),
};

/* Rx channel bonding mode */
enum wil_rx_cb_mode {
	WIL_RX_CB_MODE_DMG,
	WIL_RX_CB_MODE_EDMG,
	WIL_RX_CB_MODE_WIDE,
};

static int wil_rx_cb_mode_to_n_bonded(u8 cb_mode)
{
	switch (cb_mode) {
	case WIL_RX_CB_MODE_DMG:
	case WIL_RX_CB_MODE_EDMG:
		return 1;
	case WIL_RX_CB_MODE_WIDE:
		return 2;
	default:
		return 1;
	}
}

static int wil_tx_cb_mode_to_n_bonded(u8 cb_mode)
{
	switch (cb_mode) {
	case WMI_TX_MODE_DMG:
	case WMI_TX_MODE_EDMG_CB1:
		return 1;
	case WMI_TX_MODE_EDMG_CB2:
		return 2;
	default:
		return 1;
	}
}

static void
wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
{
@@ -167,6 +216,13 @@ void update_supported_bands(struct wil6210_priv *wil)

	wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
						wil_num_supported_channels(wil);

	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) {
		wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.channels =
							WIL_EDMG_CHANNELS;
		wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.bw_config =
						      WIL_EDMG_BW_CONFIGURATION;
	}
}

/* Vendor id to be used in vendor specific command and events
@@ -593,6 +649,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
	} __packed reply;
	struct wil_net_stats *stats = &wil->sta[cid].stats;
	int rc;
	u8 txflag = RATE_INFO_FLAGS_DMG;

	memset(&reply, 0, sizeof(reply));

@@ -606,7 +663,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
		    "  MCS %d TSF 0x%016llx\n"
		    "  BF status 0x%08x RSSI %d SQI %d%%\n"
		    "  Tx Tpt %d goodput %d Rx goodput %d\n"
		    "  Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
		    "  Sectors(rx:tx) my %d:%d peer %d:%d\n"
		    "  Tx mode %d}\n",
		    cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs),
		    le64_to_cpu(reply.evt.tsf), reply.evt.status,
		    reply.evt.rssi,
@@ -617,7 +675,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
		    le16_to_cpu(reply.evt.my_rx_sector),
		    le16_to_cpu(reply.evt.my_tx_sector),
		    le16_to_cpu(reply.evt.other_rx_sector),
		    le16_to_cpu(reply.evt.other_tx_sector));
		    le16_to_cpu(reply.evt.other_tx_sector),
		    reply.evt.tx_mode);

	sinfo->generation = wil->sinfo_gen;

@@ -630,9 +689,16 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
			BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) |
			BIT_ULL(NL80211_STA_INFO_TX_FAILED);

	sinfo->txrate.flags = RATE_INFO_FLAGS_DMG;
	if (wil->use_enhanced_dma_hw && reply.evt.tx_mode != WMI_TX_MODE_DMG)
		txflag = RATE_INFO_FLAGS_EDMG;

	sinfo->txrate.flags = txflag;
	sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
	sinfo->rxrate.mcs = stats->last_mcs_rx;
	sinfo->txrate.n_bonded_ch =
				  wil_tx_cb_mode_to_n_bonded(reply.evt.tx_mode);
	sinfo->rxrate.n_bonded_ch =
			     wil_rx_cb_mode_to_n_bonded(stats->last_cb_mode_rx);
	sinfo->rx_bytes = stats->rx_bytes;
	sinfo->rx_packets = stats->rx_packets;
	sinfo->rx_dropped_misc = stats->rx_dropped;
@@ -1310,6 +1376,33 @@ static int wil_ft_connect(struct wiphy *wiphy,
	return rc;
}

static int wil_get_wmi_edmg_channel(struct wil6210_priv *wil, u8 edmg_bw_config,
				    u8 edmg_channels, u8 *wmi_ch)
{
	if (!edmg_bw_config) {
		*wmi_ch = 0;
		return 0;
	} else if (edmg_bw_config == WIL_EDMG_BW_CONFIGURATION) {
		/* convert from edmg channel bitmap into edmg channel number */
		switch (edmg_channels) {
		case WIL_EDMG_CHANNEL_9_SUBCHANNELS:
			return wil_spec2wmi_ch(9, wmi_ch);
		case WIL_EDMG_CHANNEL_10_SUBCHANNELS:
			return wil_spec2wmi_ch(10, wmi_ch);
		case WIL_EDMG_CHANNEL_11_SUBCHANNELS:
			return wil_spec2wmi_ch(11, wmi_ch);
		default:
			wil_err(wil, "Unsupported edmg channel bitmap 0x%x\n",
				edmg_channels);
			return -EINVAL;
		}
	} else {
		wil_err(wil, "Unsupported EDMG BW configuration %d\n",
			edmg_bw_config);
		return -EINVAL;
	}
}

static int wil_cfg80211_connect(struct wiphy *wiphy,
				struct net_device *ndev,
				struct cfg80211_connect_params *sme)
@@ -1455,7 +1548,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
	conn.channel = ch - 1;

	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) {
		if (wil->force_edmg_channel) {
			rc = wil_spec2wmi_ch(wil->force_edmg_channel,
					     &conn.edmg_channel);
@@ -1463,6 +1556,14 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
				wil_err(wil,
					"wmi channel for channel %d not found",
					wil->force_edmg_channel);
		} else {
			rc = wil_get_wmi_edmg_channel(wil,
						      sme->edmg.bw_config,
						      sme->edmg.channels,
						      &conn.edmg_channel);
			if (rc < 0)
				return rc;
		}
	}

	ether_addr_copy(conn.bssid, bss->bssid);
@@ -2032,7 +2133,7 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
				  struct net_device *ndev,
				  const u8 *ssid, size_t ssid_len, u32 privacy,
				  int bi, u8 chan,
				  int bi, u8 chan, u8 wmi_edmg_channel,
				  struct cfg80211_beacon_data *bcon,
				  u8 hidden_ssid, u32 pbss)
{
@@ -2110,6 +2211,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,

	vif->privacy = privacy;
	vif->channel = chan;
	vif->wmi_edmg_channel = wmi_edmg_channel;
	vif->hidden_ssid = hidden_ssid;
	vif->pbss = pbss;
	vif->bi = bi;
@@ -2131,7 +2233,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
	}


	rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
	rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, wmi_edmg_channel,
			   hidden_ssid, is_go);
	if (rc)
		goto err_pcp_start;

@@ -2188,7 +2291,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
		rc = _wil_cfg80211_start_ap(wiphy, ndev,
					    vif->ssid, vif->ssid_len,
					    vif->privacy, vif->bi,
					    vif->channel, &bcon,
					    vif->channel,
					    vif->wmi_edmg_channel, &bcon,
					    vif->hidden_ssid, vif->pbss);
		if (rc) {
			wil_err(wil, "vif %d recovery failed (%d)\n", i, rc);
@@ -2238,7 +2342,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
		rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
					    vif->ssid_len, privacy,
					    wdev->beacon_interval,
					    vif->channel, bcon,
					    vif->channel,
					    vif->wmi_edmg_channel, bcon,
					    vif->hidden_ssid,
					    vif->pbss);
	} else {
@@ -2257,10 +2362,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
	struct ieee80211_channel *channel = info->chandef.chan;
	struct cfg80211_beacon_data *bcon = &info->beacon;
	struct cfg80211_crypto_settings *crypto = &info->crypto;
	u8 wmi_edmg_channel;
	u8 hidden_ssid;

	wil_dbg_misc(wil, "start_ap\n");

	rc = wil_get_wmi_edmg_channel(wil, info->chandef.edmg.bw_config,
				      info->chandef.edmg.channels,
				      &wmi_edmg_channel);
	if (rc < 0)
		return rc;

	if (!channel) {
		wil_err(wil, "AP: No channel???\n");
		return -EINVAL;
@@ -2300,7 +2412,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
	rc = _wil_cfg80211_start_ap(wiphy, ndev,
				    info->ssid, info->ssid_len, info->privacy,
				    info->beacon_interval, channel->hw_value,
				    bcon, hidden_ssid, info->pbss);
				    wmi_edmg_channel, bcon, hidden_ssid,
				    info->pbss);

	return rc;
}
+2 −0
Original line number Diff line number Diff line
@@ -1080,6 +1080,8 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
		stats->last_mcs_rx = wil_rx_status_get_mcs(msg);
		if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs))
			stats->rx_per_mcs[stats->last_mcs_rx]++;

		stats->last_cb_mode_rx  = wil_rx_status_get_cb_mode(msg);
	}

	if (!wil->use_rx_hw_reordering && !wil->use_compressed_rx_status &&
+6 −0
Original line number Diff line number Diff line
@@ -354,6 +354,12 @@ static inline u8 wil_rx_status_get_mcs(void *msg)
			    16, 21);
}

static inline u8 wil_rx_status_get_cb_mode(void *msg)
{
	return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1,
			    22, 23);
}

static inline u16 wil_rx_status_get_flow_id(void *msg)
{
	return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
+4 −1
Original line number Diff line number Diff line
@@ -604,6 +604,7 @@ struct wil_net_stats {
	unsigned long	rx_amsdu_error; /* eDMA specific */
	unsigned long	rx_csum_err;
	u16 last_mcs_rx;
	u8 last_cb_mode_rx;
	u64 rx_per_mcs[WIL_MCS_MAX + 1];
	u32 ft_roams; /* relevant in STA mode */
};
@@ -866,6 +867,7 @@ struct wil6210_vif {
	DECLARE_BITMAP(status, wil_vif_status_last);
	u32 privacy; /* secure connection? */
	u16 channel; /* relevant in AP mode */
	u8 wmi_edmg_channel; /* relevant in AP mode */
	u8 hidden_ssid; /* relevant in AP mode */
	u32 ap_isolate; /* no intra-BSS communication */
	bool pbss;
@@ -1396,7 +1398,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil);

int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
		  u8 hidden_ssid, u8 is_go);
		  u8 edmg_chan, u8 hidden_ssid, u8 is_go);
int wmi_pcp_stop(struct wil6210_vif *vif);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
int wmi_abort_scan(struct wil6210_vif *vif);
@@ -1506,6 +1508,7 @@ int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold);

int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch);
int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch);
void wil_update_supported_bands(struct wil6210_priv *wil);

int reverse_memcmp(const void *cs, const void *ct, size_t count);

+3 −2
Original line number Diff line number Diff line
@@ -2259,8 +2259,8 @@ int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold)
	return rc;
}

int wmi_pcp_start(struct wil6210_vif *vif,
		  int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go)
int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype,
		  u8 chan, u8 wmi_edmg_chan, u8 hidden_ssid, u8 is_go)
{
	struct wil6210_priv *wil = vif_to_wil(vif);
	int rc;
@@ -2270,6 +2270,7 @@ int wmi_pcp_start(struct wil6210_vif *vif,
		.network_type = wmi_nettype,
		.disable_sec_offload = 1,
		.channel = chan - 1,
		.edmg_channel = wmi_edmg_chan,
		.pcp_max_assoc_sta = max_assoc_sta,
		.hidden_ssid = hidden_ssid,
		.is_go = is_go,