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

Commit 92f86430 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: support FCC board file"

parents e0f702a3 75aab666
Loading
Loading
Loading
Loading
+338 −63
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@
#include "fw.h"

#define WIL_MAX_ROC_DURATION_MS 5000
#define CTRY_CHINA "CN"
#define WIL_BRD_SUFFIX_CN "CN"
#define WIL_BRD_SUFFIX_FCC "FCC"

bool disable_ap_sme;
module_param(disable_ap_sme, bool, 0444);
@@ -50,7 +51,26 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
	CHAN60G(1, 0),
	CHAN60G(2, 0),
	CHAN60G(3, 0),
/* channel 4 not supported yet */
	CHAN60G(4, 0),
};

struct wil_regd_2_brd_suffix {
	const char regdomain[3]; /* alpha2 */
	const char *brd_suffix;
};

static struct wil_regd_2_brd_suffix wil_regd_2_brd_suffix_map[] = {
	{"BO", WIL_BRD_SUFFIX_FCC},
	{"CN", WIL_BRD_SUFFIX_CN},
	{"EC", WIL_BRD_SUFFIX_FCC},
	{"GU", WIL_BRD_SUFFIX_FCC},
	{"HN", WIL_BRD_SUFFIX_FCC},
	{"JM", WIL_BRD_SUFFIX_FCC},
	{"MX", WIL_BRD_SUFFIX_FCC},
	{"NI", WIL_BRD_SUFFIX_FCC},
	{"PY", WIL_BRD_SUFFIX_FCC},
	{"TT", WIL_BRD_SUFFIX_FCC},
	{"US", WIL_BRD_SUFFIX_FCC},
};

enum wil_nl_60g_cmd_type {
@@ -96,6 +116,26 @@ struct wil_nl_60g_debug_force_wmi {
	u32 enable;
} __packed;

static int wil_num_supported_channels(struct wil6210_priv *wil)
{
	int num_channels = ARRAY_SIZE(wil_60ghz_channels);

	if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities))
		num_channels--;

	return num_channels;
}

void update_supported_bands(struct wil6210_priv *wil)
{
	struct wiphy *wiphy = wil_to_wiphy(wil);

	wil_dbg_misc(wil, "update supported bands");

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

/* Vendor id to be used in vendor specific command and events
 * to user space.
 * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
@@ -362,7 +402,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
		BIT(IEEE80211_STYPE_DISASSOC >> 4),
		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
		BIT(IEEE80211_STYPE_AUTH >> 4) |
		BIT(IEEE80211_STYPE_REASSOC_RESP >> 4),
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
		BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
@@ -1114,6 +1156,26 @@ static void wil_print_crypto(struct wil6210_priv *wil,
		     c->control_port_no_encrypt);
}

static const char *
wil_get_auth_type_name(enum nl80211_auth_type auth_type)
{
	switch (auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		return "OPEN_SYSTEM";
	case NL80211_AUTHTYPE_SHARED_KEY:
		return "SHARED_KEY";
	case NL80211_AUTHTYPE_FT:
		return "FT";
	case NL80211_AUTHTYPE_NETWORK_EAP:
		return "NETWORK_EAP";
	case NL80211_AUTHTYPE_SAE:
		return "SAE";
	case NL80211_AUTHTYPE_AUTOMATIC:
		return "AUTOMATIC";
	default:
		return "unknown";
	}
}
static void wil_print_connect_params(struct wil6210_priv *wil,
				     struct cfg80211_connect_params *sme)
{
@@ -1127,11 +1189,82 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
	if (sme->ssid)
		print_hex_dump(KERN_INFO, "  SSID: ", DUMP_PREFIX_OFFSET,
			       16, 1, sme->ssid, sme->ssid_len, true);
	if (sme->prev_bssid)
		wil_info(wil, "  Previous BSSID=%pM\n", sme->prev_bssid);
	wil_info(wil, "  Auth Type: %s\n",
		 wil_get_auth_type_name(sme->auth_type));
	wil_info(wil, "  Privacy: %s\n", sme->privacy ? "secure" : "open");
	wil_info(wil, "  PBSS: %d\n", sme->pbss);
	wil_print_crypto(wil, &sme->crypto);
}

static int wil_ft_connect(struct wiphy *wiphy,
			  struct net_device *ndev,
			  struct cfg80211_connect_params *sme)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_vif *vif = ndev_to_vif(ndev);
	struct wmi_ft_auth_cmd auth_cmd;
	int rc;

	if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
		wil_err(wil, "FT: FW does not support FT roaming\n");
		return -EOPNOTSUPP;
	}

	if (!sme->prev_bssid) {
		wil_err(wil, "FT: prev_bssid was not set\n");
		return -EINVAL;
	}

	if (ether_addr_equal(sme->prev_bssid, sme->bssid)) {
		wil_err(wil, "FT: can not roam to same AP\n");
		return -EINVAL;
	}

	if (!test_bit(wil_vif_fwconnected, vif->status)) {
		wil_err(wil, "FT: roam while not connected\n");
		return -EINVAL;
	}

	if (vif->privacy != sme->privacy) {
		wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n",
			vif->privacy, sme->privacy);
		return -EINVAL;
	}

	if (sme->pbss) {
		wil_err(wil, "FT: roam is not valid for PBSS\n");
		return -EINVAL;
	}

	memset(&auth_cmd, 0, sizeof(auth_cmd));
	auth_cmd.channel = sme->channel->hw_value - 1;
	ether_addr_copy(auth_cmd.bssid, sme->bssid);

	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
		if (wil->force_edmg_channel) {
			rc = wil_spec2wmi_ch(wil->force_edmg_channel,
					     &auth_cmd.channel);
			if (rc)
				wil_err(wil, "FT: wmi channel for channel %d not found",
					wil->force_edmg_channel);
		}

	wil_info(wil, "FT: roaming\n");

	set_bit(wil_vif_ft_roam, vif->status);
	rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid,
		      &auth_cmd, sizeof(auth_cmd));
	if (rc == 0)
		mod_timer(&vif->connect_timer,
			  jiffies + msecs_to_jiffies(5000));
	else
		clear_bit(wil_vif_ft_roam, vif->status);

	return rc;
}

static int wil_cfg80211_connect(struct wiphy *wiphy,
				struct net_device *ndev,
				struct cfg80211_connect_params *sme)
@@ -1144,11 +1277,20 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	const u8 *rsn_eid;
	int ch;
	int rc = 0;
	bool is_ft_roam = false;
	u8 network_type;
	enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;

	wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
	wil_print_connect_params(wil, sme);

	if (sme->auth_type == NL80211_AUTHTYPE_FT)
		is_ft_roam = true;
	if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC &&
	    test_bit(wil_vif_fwconnected, vif->status))
		is_ft_roam = true;

	if (!is_ft_roam)
		if (test_bit(wil_vif_fwconnecting, vif->status) ||
		    test_bit(wil_vif_fwconnected, vif->status))
			return -EALREADY;
@@ -1161,8 +1303,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	rsn_eid = sme->ie ?
			cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
			NULL;
	if (sme->privacy && !rsn_eid)
	if (sme->privacy && !rsn_eid) {
		wil_info(wil, "WSC connection\n");
		if (is_ft_roam) {
			wil_err(wil, "No WSC with FT roam\n");
			return -EINVAL;
		}
	}

	if (sme->pbss)
		bss_type = IEEE80211_BSS_TYPE_PBSS;
@@ -1184,6 +1331,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	vif->privacy = sme->privacy;
	vif->pbss = sme->pbss;

	rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
	if (rc)
		goto out;

	switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
	case WLAN_CAPABILITY_DMG_TYPE_AP:
		network_type = WMI_NETTYPE_INFRA;
		break;
	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
		network_type = WMI_NETTYPE_P2P;
		break;
	default:
		wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
			bss->capability);
		rc = -EINVAL;
		goto out;
	}

	ch = bss->channel->hw_value;
	if (ch == 0) {
		wil_err(wil, "BSS at unknown frequency %dMhz\n",
			bss->channel->center_freq);
		rc = -EOPNOTSUPP;
		goto out;
	}

	if (is_ft_roam) {
		if (network_type != WMI_NETTYPE_INFRA) {
			wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n",
				bss->capability);
			rc = -EINVAL;
			goto out;
		}
		rc = wil_ft_connect(wiphy, ndev, sme);
		if (rc == 0)
			vif->bss = bss;
		goto out;
	}

	if (vif->privacy) {
		/* For secure assoc, remove old keys */
		rc = wmi_del_cipher_key(vif, 0, bss->bssid,
@@ -1200,28 +1386,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
		}
	}

	/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
	 * elements. Send it also in case it's empty, to erase previously set
	 * ies in FW.
	 */
	rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
	if (rc)
		goto out;

	/* WMI_CONNECT_CMD */
	memset(&conn, 0, sizeof(conn));
	switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
	case WLAN_CAPABILITY_DMG_TYPE_AP:
		conn.network_type = WMI_NETTYPE_INFRA;
		break;
	case WLAN_CAPABILITY_DMG_TYPE_PBSS:
		conn.network_type = WMI_NETTYPE_P2P;
		break;
	default:
		wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
			bss->capability);
		goto out;
	}
	conn.network_type = network_type;
	if (vif->privacy) {
		if (rsn_eid) { /* regular secure connection */
			conn.dot11_auth_mode = WMI_AUTH11_SHARED;
@@ -1241,14 +1408,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,

	conn.ssid_len = min_t(u8, ssid_eid[1], 32);
	memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);

	ch = bss->channel->hw_value;
	if (ch == 0) {
		wil_err(wil, "BSS at unknown frequency %dMhz\n",
			bss->channel->center_freq);
		rc = -EOPNOTSUPP;
		goto out;
	}
	conn.channel = ch - 1;

	if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities))
@@ -1454,7 +1613,7 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
	return &wil->sta[cid];
}

static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
		       struct wil_sta_info *cs,
		       struct key_params *params)
{
@@ -1539,12 +1698,18 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
		     params->seq_len, params->seq);

	if (IS_ERR(cs)) {
		/* in FT, sta info may not be available as add_key may be
		 * sent by host before FW sends WMI_CONNECT_EVENT
		 */
		if (!test_bit(wil_vif_ft_roam, vif->status)) {
			wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
				mac_addr, key_usage_str[key_usage], key_index,
				params->seq_len, params->seq);
			return -EINVAL;
		}
	}

	if (!IS_ERR(cs))
		wil_del_rx_key(key_index, key_usage, cs);

	if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
@@ -1558,7 +1723,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,

	rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
				params->key, key_usage);
	if (!rc)
	if (!rc && !IS_ERR(cs))
		/* in FT set crypto will take place upon receiving
		 * WMI_RING_EN_EVENTID event
		 */
		wil_set_crypto_rx(key_index, key_usage, cs, params);

	return rc;
@@ -1721,21 +1889,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
}

/* internal functions for device reset and starting AP */
static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
				 struct cfg80211_beacon_data *bcon)
static u8 *
_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len,
				u16 *ies_len)
{
	int rc;
	u16 len = 0, proberesp_len = 0;
	u8 *ies = NULL, *proberesp = NULL;
	u8 *ies = NULL;

	if (bcon->probe_resp) {
	if (proberesp) {
		struct ieee80211_mgmt *f =
			(struct ieee80211_mgmt *)bcon->probe_resp;
			(struct ieee80211_mgmt *)proberesp;
		size_t hlen = offsetof(struct ieee80211_mgmt,
				       u.probe_resp.variable);
		proberesp = f->u.probe_resp.variable;
		proberesp_len = bcon->probe_resp_len - hlen;

		ies = f->u.probe_resp.variable;
		if (ies_len)
			*ies_len = proberesp_len - hlen;
	}

	return ies;
}

static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
				 struct cfg80211_beacon_data *bcon)
{
	int rc;
	u16 len = 0, proberesp_len = 0;
	u8 *ies = NULL, *proberesp;

	proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
						    bcon->probe_resp_len,
						    &proberesp_len);
	rc = _wil_cfg80211_merge_extra_ies(proberesp,
					   proberesp_len,
					   bcon->proberesp_ies,
@@ -1779,6 +1962,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
	struct wireless_dev *wdev = ndev->ieee80211_ptr;
	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
	u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
	u16 proberesp_len = 0;
	u8 *proberesp;
	bool ft = false;

	if (pbss)
		wmi_nettype = WMI_NETTYPE_P2P;
@@ -1791,6 +1977,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,

	wil_set_recovery_state(wil, fw_recovery_idle);

	proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
						    bcon->probe_resp_len,
						    &proberesp_len);
	/* check that the probe response IEs has a MDE */
	if ((proberesp && proberesp_len > 0 &&
	     cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN,
			      proberesp,
			      proberesp_len)))
		ft = true;

	if (ft) {
		if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING,
			      wil->fw_capabilities)) {
			wil_err(wil, "FW does not support FT roaming\n");
			return -ENOTSUPP;
		}
		set_bit(wil_vif_ft_roam, vif->status);
	}

	mutex_lock(&wil->mutex);

	if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
@@ -1952,6 +2157,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
	mutex_lock(&wil->mutex);

	wmi_pcp_stop(vif);
	clear_bit(wil_vif_ft_roam, vif->status);

	if (last)
		__wil_down(wil);
@@ -1971,8 +2177,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
	struct wil6210_vif *vif = ndev_to_vif(dev);
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);

	wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
		     mac, params->aid, vif->mid);
	wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n",
		     mac, params->aid, vif->mid,
		     params->sta_flags_mask, params->sta_flags_set);

	if (!disable_ap_sme) {
		wil_err(wil, "not supported with AP SME enabled\n");
@@ -2294,24 +2501,43 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
	return 0;
}

static void wil_get_brd_reg_suffix(struct wil6210_priv *wil,
				   const u8 *new_regdomain,
				   char *brd_reg_suffix, size_t len)
{
	int i;
	struct wil_regd_2_brd_suffix *entry;

	for (i = 0; i < ARRAY_SIZE(wil_regd_2_brd_suffix_map); i++) {
		entry = &wil_regd_2_brd_suffix_map[i];
		if (!memcmp(entry->regdomain, new_regdomain, 2)) {
			strlcpy(brd_reg_suffix, entry->brd_suffix, len);
			return;
		}
	}

	/* regdomain not found in our map, set suffix to none */
	brd_reg_suffix[0] = '\0';
}

static int wil_switch_board_file(struct wil6210_priv *wil,
				 const u8 *new_regdomain)
{
	int rc = 0;
	char brd_reg_suffix[WIL_BRD_SUFFIX_LEN];

	if (!country_specific_board_file)
		return 0;

	if (memcmp(wil->regdomain, CTRY_CHINA, 2) == 0) {
		wil_info(wil, "moving out of China reg domain, use default board file\n");
		wil->board_file_country[0] = '\0';
	} else if (memcmp(new_regdomain, CTRY_CHINA, 2) == 0) {
		wil_info(wil, "moving into China reg domain, use country specific board file\n");
		strlcpy(wil->board_file_country, CTRY_CHINA,
			sizeof(wil->board_file_country));
	} else {
	wil_get_brd_reg_suffix(wil, new_regdomain, brd_reg_suffix,
			       sizeof(brd_reg_suffix));
	if (!strcmp(wil->board_file_reg_suffix, brd_reg_suffix))
		return 0;
	}

	wil_info(wil, "switch board file suffix '%s' => '%s'\n",
		 wil->board_file_reg_suffix, brd_reg_suffix);
	strlcpy(wil->board_file_reg_suffix, brd_reg_suffix,
		sizeof(wil->board_file_reg_suffix));

	/* need to switch board file - reset the device */

@@ -2353,6 +2579,54 @@ static void wil_cfg80211_reg_notify(struct wiphy *wiphy,
	memcpy(wil->regdomain, request->alpha2, 2);
}

static int
wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
			   struct cfg80211_update_ft_ies_params *ftie)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct wil6210_vif *vif = ndev_to_vif(dev);
	struct cfg80211_bss *bss;
	struct wmi_ft_reassoc_cmd reassoc;
	int rc = 0;

	wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid);
	wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1,
			  ftie->ie, ftie->ie_len, true);

	if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
		wil_err(wil, "FW does not support FT roaming\n");
		return -EOPNOTSUPP;
	}

	rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie);
	if (rc)
		return rc;

	if (!test_bit(wil_vif_ft_roam, vif->status))
		/* vif is not roaming */
		return 0;

	/* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as
	 * a trigger for reassoc
	 */

	bss = vif->bss;
	if (!bss) {
		wil_err(wil, "FT: bss is NULL\n");
		return -EINVAL;
	}

	memset(&reassoc, 0, sizeof(reassoc));
	ether_addr_copy(reassoc.bssid, bss->bssid);

	rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid,
		      &reassoc, sizeof(reassoc));
	if (rc)
		wil_err(wil, "FT: reassoc failed (%d)\n", rc);

	return rc;
}

static const struct cfg80211_ops wil_cfg80211_ops = {
	.add_virtual_intf = wil_cfg80211_add_iface,
	.del_virtual_intf = wil_cfg80211_del_iface,
@@ -2388,6 +2662,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
	.resume = wil_cfg80211_resume,
	.sched_scan_start = wil_cfg80211_sched_scan_start,
	.sched_scan_stop = wil_cfg80211_sched_scan_stop,
	.update_ft_ies = wil_cfg80211_update_ft_ies,
};

static void wil_wiphy_init(struct wiphy *wiphy)
+18 −29
Original line number Diff line number Diff line
@@ -714,32 +714,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
	return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
}

/*---reset---*/
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
				    size_t len, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	struct net_device *ndev = wil->main_ndev;

	/**
	 * BUG:
	 * this code does NOT sync device state with the rest of system
	 * use with care, debug only!!!
	 */
	rtnl_lock();
	dev_close(ndev);
	ndev->flags &= ~IFF_UP;
	rtnl_unlock();
	wil_reset(wil, true);

	return len;
}

static const struct file_operations fops_reset = {
	.write = wil_write_file_reset,
	.open  = simple_open,
};

/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
				   size_t len, loff_t *ppos)
@@ -1252,6 +1226,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
	int num_active;
	int num_free;

	if (!rbm->buff_arr)
		return -EINVAL;

	seq_printf(s, "  size = %zu\n", rbm->size);
	seq_printf(s, "  free_list_empty_cnt = %lu\n",
		   rbm->free_list_empty_cnt);
@@ -1684,6 +1661,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
		char *status = "unknown";
		u8 aid = 0;
		u8 mid;
		bool sta_connected = false;

		switch (p->status) {
		case wil_sta_unused:
@@ -1698,8 +1676,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			break;
		}
		mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
		seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
			   mid, aid);
		if (mid < wil->max_vifs) {
			struct wil6210_vif *vif = wil->vifs[mid];

			if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
			    p->status == wil_sta_connected)
				sta_connected = true;
		}
		/* print roam counter only for connected stations */
		if (sta_connected)
			seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
				   i, p->addr, p->stats.ft_roams, mid, aid);
		else
			seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
				   p->addr, status, mid, aid);

		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
@@ -2440,7 +2430,6 @@ static const struct {
	{"desc",	0444,		&fops_txdesc},
	{"bf",		0444,		&fops_bf},
	{"mem_val",	0644,		&fops_memread},
	{"reset",	0244,		&fops_reset},
	{"rxon",	0244,		&fops_rxon},
	{"tx_mgmt",	0244,		&fops_txmgmt},
	{"wmi_send", 0244,		&fops_wmi},
+14 −5
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ static const struct kernel_param_ops mtu_max_ops = {
module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
MODULE_PARM_DESC(mtu_max, " Max MTU value.");

static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint rx_ring_order;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;

@@ -351,6 +351,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
			vif->bss = NULL;
		}
		clear_bit(wil_vif_fwconnecting, vif->status);
		clear_bit(wil_vif_ft_roam, vif->status);

		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
@@ -1146,6 +1148,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
		wil->max_agg_wsize = WIL_MAX_AGG_WSIZE;
		wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE;
	}

	update_supported_bands(wil);
}

void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
@@ -1178,19 +1182,19 @@ void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len)
			board_file = WIL_BOARD_FILE_NAME;
	}

	if (wil->board_file_country[0] == '\0') {
	if (wil->board_file_reg_suffix[0] == '\0') {
		strlcpy(buf, board_file, len);
		return;
	}

	/* use country specific board file */
	if (len < strlen(board_file) + 4 /* for _XX and terminating null */)
	if (len < strlen(board_file) + 1 + WIL_BRD_SUFFIX_LEN) /* 1 for '_' */
		return;

	ext = strrchr(board_file, '.');
	prefix_len = (ext ? ext - board_file : strlen(board_file));
	snprintf(buf, len, "%.*s_%.2s",
		 prefix_len, board_file, wil->board_file_country);
	snprintf(buf, len, "%.*s_%.3s",
		 prefix_len, board_file, wil->board_file_reg_suffix);
	if (ext)
		strlcat(buf, ext, len);
}
@@ -1699,6 +1703,11 @@ int __wil_up(struct wil6210_priv *wil)
		return rc;

	/* Rx RING. After MAC and beacon */
	if (rx_ring_order == 0)
		rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ?
			WIL_RX_RING_SIZE_ORDER_DEFAULT :
			WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT;

	rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order);
	if (rc)
		return rc;
+83 −0
Original line number Diff line number Diff line
@@ -1048,6 +1048,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
	return rc;
}

static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
			       int tid)
{
	struct wil6210_priv *wil = vif_to_wil(vif);
	int rc;
	struct wmi_vring_cfg_cmd cmd = {
		.action = cpu_to_le32(WMI_VRING_CMD_MODIFY),
		.vring_cfg = {
			.tx_sw_ring = {
				.max_mpdu_size =
					cpu_to_le16(wil_mtu2macbuf(mtu_max)),
				.ring_size = 0,
			},
			.ringid = ring_id,
			.cidxtid = mk_cidxtid(cid, tid),
			.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
			.mac_ctrl = 0,
			.to_resolution = 0,
			.agg_max_wsize = 0,
			.schd_params = {
				.priority = cpu_to_le16(0),
				.timeslot_us = cpu_to_le16(0xfff),
			},
		},
	};
	struct {
		struct wmi_cmd_hdr wmi;
		struct wmi_vring_cfg_done_event cmd;
	} __packed reply = {
		.cmd = {.status = WMI_FW_STATUS_FAILURE},
	};
	struct wil_ring *vring = &wil->ring_tx[ring_id];
	struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];

	wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id,
		     cid, tid);
	lockdep_assert_held(&wil->mutex);

	if (!vring->va) {
		wil_err(wil, "Tx ring [%d] not allocated\n", ring_id);
		return -EINVAL;
	}

	if (wil->ring2cid_tid[ring_id][0] != cid ||
	    wil->ring2cid_tid[ring_id][1] != tid) {
		wil_err(wil, "ring info does not match cid=%u tid=%u\n",
			wil->ring2cid_tid[ring_id][0],
			wil->ring2cid_tid[ring_id][1]);
	}

	cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);

	rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
		      WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
	if (rc)
		goto fail;

	if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
		wil_err(wil, "Tx modify failed, status 0x%02x\n",
			reply.cmd.status);
		rc = -EINVAL;
		goto fail;
	}

	/* set BA aggregation window size to 0 to force a new BA with the
	 * new AP
	 */
	txdata->agg_wsize = 0;
	if (txdata->dot1x_open && agg_wsize >= 0)
		wil_addba_tx_request(wil, ring_id, agg_wsize);

	return 0;
fail:
	spin_lock_bh(&txdata->lock);
	txdata->dot1x_open = false;
	txdata->enabled = 0;
	spin_unlock_bh(&txdata->lock);
	wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
	wil->ring2cid_tid[ring_id][1] = 0;
	return rc;
}

int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
{
	struct wil6210_priv *wil = vif_to_wil(vif);
@@ -2270,6 +2352,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
	wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
	wil->txrx_ops.tx_init = wil_tx_init;
	wil->txrx_ops.tx_fini = wil_tx_fini;
	wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify;
	/* RX ops */
	wil->txrx_ops.rx_init = wil_rx_init;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;
+13 −2
Original line number Diff line number Diff line
@@ -357,8 +357,8 @@ static int wil_init_rx_sring(struct wil6210_priv *wil,
	struct wil_status_ring *sring = &wil->srings[ring_id];
	int rc;

	wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size,
		     ring_id);
	wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n",
		     status_ring_size, ring_id);

	memset(&sring->rx_data, 0, sizeof(sring->rx_data));

@@ -747,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
	return rc;
}

static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
				   int cid, int tid)
{
	struct wil6210_priv *wil = vif_to_wil(vif);

	wil_err(wil, "ring modify is not supported for EDMA\n");

	return -EOPNOTSUPP;
}

/* This function is used only for RX SW reorder */
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
			 struct sk_buff *skb, struct wil_net_stats *stats)
@@ -1600,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
	wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
	wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
	wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
	wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma;
	/* RX ops */
	wil->txrx_ops.rx_init = wil_rx_init_edma;
	wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;
Loading