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

Commit 4b073182 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Merge remote-tracking branch 'remotes/origin/tmp-43a59d14' into msm-3.18"

parents 0221c3fa e185f3ed
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-y += ioctl.o
wil6210-y += fw.o
wil6210-y += pmc.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
wil6210-y += ethtool.o
+165 −43
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <linux/etherdevice.h>
#include "wil6210.h"
#include "wmi.h"

@@ -217,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy,
	if (cid < 0)
		return -ENOENT;

	memcpy(mac, wil->sta[cid].addr, ETH_ALEN);
	ether_addr_copy(mac, wil->sta[cid].addr);
	wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid);

	rc = wil_cid_fill_sinfo(wil, cid, sinfo);
@@ -288,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
	}

	wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
	wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);

	for (i = 0; i < request->n_ssids; i++) {
		wil_dbg_misc(wil, "SSID[%d]", i);
		print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
				     request->ssids[i].ssid,
				     request->ssids[i].ssid_len);
	}

	if (request->n_ssids)
		rc = wmi_set_ssid(wil, request->ssids[0].ssid_len,
				  request->ssids[0].ssid);
	else
		rc = wmi_set_ssid(wil, 0, NULL);

	if (rc) {
		wil_err(wil, "set SSID for scan request failed: %d\n", rc);
		return rc;
	}

	wil->scan_request = request;
	mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);

@@ -401,11 +422,8 @@ 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) {
		wil_err(wil, "Missing RSN IE for secure connection\n");
		return -EINVAL;
	}
	if (sme->privacy && !rsn_eid)
		wil_info(wil, "WSC connection\n");

	bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
			       sme->ssid, sme->ssid_len,
@@ -424,10 +442,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	wil->privacy = sme->privacy;

	if (wil->privacy) {
		/* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
		rc = wmi_del_cipher_key(wil, 0, bss->bssid);
		/* For secure assoc, remove old keys */
		rc = wmi_del_cipher_key(wil, 0, bss->bssid,
					WMI_KEY_USE_PAIRWISE);
		if (rc) {
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
			goto out;
		}
		rc = wmi_del_cipher_key(wil, 0, bss->bssid,
					WMI_KEY_USE_RX_GROUP);
		if (rc) {
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
			goto out;
		}
	}
@@ -457,11 +482,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
		goto out;
	}
	if (wil->privacy) {
		if (rsn_eid) { /* regular secure connection */
			conn.dot11_auth_mode = WMI_AUTH11_SHARED;
			conn.auth_mode = WMI_AUTH_WPA2_PSK;
			conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
			conn.pairwise_crypto_len = 16;
	} else {
			conn.group_crypto_type = WMI_CRYPT_AES_GCMP;
			conn.group_crypto_len = 16;
		} else { /* WSC */
			conn.dot11_auth_mode = WMI_AUTH11_WSC;
			conn.auth_mode = WMI_AUTH_NONE;
		}
	} else { /* insecure connection */
		conn.dot11_auth_mode = WMI_AUTH11_OPEN;
		conn.auth_mode = WMI_AUTH_NONE;
	}
@@ -478,8 +510,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
	}
	conn.channel = ch - 1;

	memcpy(conn.bssid, bss->bssid, ETH_ALEN);
	memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);
	ether_addr_copy(conn.bssid, bss->bssid);
	ether_addr_copy(conn.dst_mac, bss->bssid);

	set_bit(wil_status_fwconnecting, wil->status);

@@ -506,6 +538,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
	int rc;
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);

	wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);

	rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	return rc;
@@ -560,6 +594,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy,
	return 0;
}

static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil,
					       bool pairwise)
{
	struct wireless_dev *wdev = wil->wdev;
	enum wmi_key_usage rc;
	static const char * const key_usage_str[] = {
		[WMI_KEY_USE_PAIRWISE]	= "WMI_KEY_USE_PAIRWISE",
		[WMI_KEY_USE_RX_GROUP]	= "WMI_KEY_USE_RX_GROUP",
		[WMI_KEY_USE_TX_GROUP]	= "WMI_KEY_USE_TX_GROUP",
	};

	if (pairwise) {
		rc = WMI_KEY_USE_PAIRWISE;
	} else {
		switch (wdev->iftype) {
		case NL80211_IFTYPE_STATION:
			rc = WMI_KEY_USE_RX_GROUP;
			break;
		case NL80211_IFTYPE_AP:
			rc = WMI_KEY_USE_TX_GROUP;
			break;
		default:
			/* TODO: Rx GTK or Tx GTK? */
			wil_err(wil, "Can't determine GTK type\n");
			rc = WMI_KEY_USE_RX_GROUP;
			break;
		}
	}
	wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]);

	return rc;
}

static int wil_cfg80211_add_key(struct wiphy *wiphy,
				struct net_device *ndev,
				u8 key_index, bool pairwise,
@@ -567,13 +634,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
				struct key_params *params)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);

	/* group key is not used */
	if (!pairwise)
		return 0;
	wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
		     pairwise ? "PTK" : "GTK");

	return wmi_add_cipher_key(wil, key_index, mac_addr,
				  params->key_len, params->key);
	return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len,
				  params->key, key_usage);
}

static int wil_cfg80211_del_key(struct wiphy *wiphy,
@@ -582,12 +649,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy,
				const u8 *mac_addr)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise);

	/* group key is not used */
	if (!pairwise)
		return 0;
	wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index,
		     pairwise ? "PTK" : "GTK");

	return wmi_del_cipher_key(wil, key_index, mac_addr);
	return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage);
}

/* Need to be present or wiphy_new() will WARN */
@@ -660,11 +727,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil,
	if (bcon->probe_resp_len <= hlen)
		return 0;

	if (!bcon->proberesp_ies) {
		bcon->proberesp_ies = f->u.probe_resp.variable;
		bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
		rc = 1;
	}
	if (!bcon->assocresp_ies) {
		bcon->assocresp_ies = f->u.probe_resp.variable;
		bcon->assocresp_ies_len = bcon->probe_resp_len - hlen;
@@ -679,9 +741,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
				      struct cfg80211_beacon_data *bcon)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
	size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
	const u8 *pr_ies = NULL;
	size_t pr_ies_len = 0;
	int rc;

	wil_dbg_misc(wil, "%s()\n", __func__);
	wil_print_bcon_data(bcon);

	if (bcon->probe_resp_len > hlen) {
		pr_ies = f->u.probe_resp.variable;
		pr_ies_len = bcon->probe_resp_len - hlen;
	}

	if (wil_fix_bcon(wil, bcon)) {
		wil_dbg_misc(wil, "Fixed bcon\n");
@@ -694,9 +766,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
	 * bcon->beacon_ies);
	 */
	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
			bcon->proberesp_ies_len,
			bcon->proberesp_ies);
	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
	if (rc) {
		wil_err(wil, "set_ie(PROBE_RESP) failed\n");
		return rc;
@@ -724,6 +794,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
	struct cfg80211_beacon_data *bcon = &info->beacon;
	struct cfg80211_crypto_settings *crypto = &info->crypto;
	u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
	struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
	size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
	const u8 *pr_ies = NULL;
	size_t pr_ies_len = 0;
	u8 hidden_ssid;

	wil_dbg_misc(wil, "%s()\n", __func__);

@@ -736,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
		     channel->center_freq, info->privacy ? "secure" : "open");
	wil_dbg_misc(wil, "Privacy: %d auth_type %d\n",
		     info->privacy, info->auth_type);
	wil_dbg_misc(wil, "Hidden SSID mode: %d\n",
		     info->hidden_ssid);
	wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
		     info->dtim_period);
	print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
@@ -743,6 +820,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
	wil_print_bcon_data(bcon);
	wil_print_crypto(wil, crypto);

	if (bcon->probe_resp_len > hlen) {
		pr_ies = f->u.probe_resp.variable;
		pr_ies_len = bcon->probe_resp_len - hlen;
	}

	if (wil_fix_bcon(wil, bcon)) {
		wil_dbg_misc(wil, "Fixed bcon\n");
		wil_print_bcon_data(bcon);
@@ -770,20 +852,46 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
	 * bcon->beacon_ies);
	 */
	wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
		   bcon->proberesp_ies);
	wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies);
	wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
		   bcon->assocresp_ies);

	wil->privacy = info->privacy;

	switch (info->hidden_ssid) {
	case NL80211_HIDDEN_SSID_NOT_IN_USE:
		hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
		break;

	case NL80211_HIDDEN_SSID_ZERO_LEN:
		hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY;
		break;

	case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
		hidden_ssid = WMI_HIDDEN_SSID_CLEAR;
		break;

	default:
		rc = -EOPNOTSUPP;
		goto out;
	}

	netif_carrier_on(ndev);

	rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
			   channel->hw_value);
			   channel->hw_value, hidden_ssid);
	if (rc)
		netif_carrier_off(ndev);
		goto err_pcp_start;

	rc = wil_bcast_init(wil);
	if (rc)
		goto err_bcast;

	goto out; /* success */
err_bcast:
	wmi_pcp_stop(wil);
err_pcp_start:
	netif_carrier_off(ndev);
out:
	mutex_unlock(&wil->mutex);
	return rc;
@@ -804,13 +912,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
	wmi_pcp_stop(wil);

	__wil_down(wil);
	__wil_up(wil);

	mutex_unlock(&wil->mutex);

	/* some functions above might fail (e.g. __wil_up). Nevertheless, we
	 * return success because AP has stopped
	 */
	return 0;
}

@@ -819,6 +923,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);

	wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, mac,
		     WLAN_REASON_UNSPECIFIED);

	mutex_lock(&wil->mutex);
	wil6210_disconnect(wil, mac, WLAN_REASON_UNSPECIFIED, false);
	mutex_unlock(&wil->mutex);
@@ -916,6 +1023,21 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy,
	return 0;
}

static int wil_cfg80211_change_bss(struct wiphy *wiphy,
				   struct net_device *dev,
				   struct bss_parameters *params)
{
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);

	if (params->ap_isolate >= 0) {
		wil_dbg_misc(wil, "%s(ap_isolate %d => %d)\n", __func__,
			     wil->ap_isolate, params->ap_isolate);
		wil->ap_isolate = params->ap_isolate;
	}

	return 0;
}

static struct cfg80211_ops wil_cfg80211_ops = {
	.scan = wil_cfg80211_scan,
	.connect = wil_cfg80211_connect,
@@ -936,12 +1058,12 @@ static struct cfg80211_ops wil_cfg80211_ops = {
	.stop_ap = wil_cfg80211_stop_ap,
	.del_station = wil_cfg80211_del_station,
	.probe_client = wil_cfg80211_probe_client,
	.change_bss = wil_cfg80211_change_bss,
};

static void wil_wiphy_init(struct wiphy *wiphy)
{
	/* TODO: set real value */
	wiphy->max_scan_ssids = 10;
	wiphy->max_scan_ssids = 1;
	wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
	wiphy->max_num_pmkids = 0 /* TODO: */;
	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+119 −13
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
 * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
@@ -24,6 +24,7 @@
#include "wil6210.h"
#include "wmi.h"
#include "txrx.h"
#include "pmc.h"

/* Nasty hack. Better have per device instances */
static u32 mem_addr;
@@ -121,12 +122,20 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)

			snprintf(name, sizeof(name), "tx_%2d", i);

			if (cid < WIL6210_MAX_CID)
				seq_printf(s,
				"\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n",
					   "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n",
					   wil->sta[cid].addr, cid, tid,
				txdata->agg_wsize, txdata->agg_timeout,
					   txdata->dot1x_open ? "+" : "-",
					   txdata->agg_wsize,
					   txdata->agg_timeout,
					   txdata->agg_amsdu ? "+" : "-",
					   used, avail, sidle);
			else
				seq_printf(s,
					   "\nBroadcast 1x%s [%3d|%3d] idle %s\n",
					   txdata->dot1x_open ? "+" : "-",
					   used, avail, sidle);

			wil_print_vring(s, wil, name, vring, '_', 'H');
		}
@@ -626,7 +635,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
	struct wil6210_priv *wil = file->private_data;
	int rc;
	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
	char cmd[8];
	char cmd[9];
	int p1, p2, p3;

	if (!kbuf)
@@ -696,6 +705,89 @@ static const struct file_operations fops_back = {
	.open  = simple_open,
};

/* pmc control, write:
 * - "alloc <num descriptors> <descriptor_size>" to allocate PMC
 * - "free" to release memory allocated for PMC
 */
static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf,
				size_t len, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	int rc;
	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
	char cmd[9];
	int num_descs, desc_size;

	if (!kbuf)
		return -ENOMEM;

	rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
	if (rc != len) {
		kfree(kbuf);
		return rc >= 0 ? -EIO : rc;
	}

	kbuf[len] = '\0';
	rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size);
	kfree(kbuf);

	if (rc < 0)
		return rc;

	if (rc < 1) {
		wil_err(wil, "pmccfg: no params given\n");
		return -EINVAL;
	}

	if (0 == strcmp(cmd, "alloc")) {
		if (rc != 3) {
			wil_err(wil, "pmccfg: alloc requires 2 params\n");
			return -EINVAL;
		}
		wil_pmc_alloc(wil, num_descs, desc_size);
	} else if (0 == strcmp(cmd, "free")) {
		if (rc != 1) {
			wil_err(wil, "pmccfg: free does not have any params\n");
			return -EINVAL;
		}
		wil_pmc_free(wil, true);
	} else {
		wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd);
		return -EINVAL;
	}

	return len;
}

static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf,
			       size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	char text[256];
	char help[] = "pmc control, write:\n"
	" - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n"
	" - \"free\" to free memory allocated for pmc\n";

	sprintf(text, "Last command status: %d\n\n%s",
		wil_pmc_last_cmd_status(wil),
		help);

	return simple_read_from_buffer(user_buf, count, ppos, text,
				       strlen(text) + 1);
}

static const struct file_operations fops_pmccfg = {
	.read = wil_read_pmccfg,
	.write = wil_write_pmccfg,
	.open  = simple_open,
};

static const struct file_operations fops_pmcdata = {
	.open		= simple_open,
	.read		= wil_pmc_read,
	.llseek		= wil_pmc_llseek,
};

/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -1105,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
			status = "connected";
			break;
		}
		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
			   (p->data_port_open ? " data_port_open" : ""));
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);

		if (p->status == wil_sta_connected) {
			rc = wil_cid_fill_sinfo(wil, i, &sinfo);
@@ -1269,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{
	struct wil6210_priv *wil = s->private;
	int i, tid;
	int i, tid, mcs;

	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		struct wil_sta_info *p = &wil->sta[i];
@@ -1286,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
			status = "connected";
			break;
		}
		seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status,
			   (p->data_port_open ? " data_port_open" : ""));
		seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);

		if (p->status == wil_sta_connected) {
			spin_lock_bh(&p->tid_rx_lock);
@@ -1300,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
				}
			}
			spin_unlock_bh(&p->tid_rx_lock);
			seq_puts(s, "Rx/MCS:");
			for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
			     mcs++)
				seq_printf(s, " %lld",
					   p->stats.rx_per_mcs[mcs]);
			seq_puts(s, "\n");
		}
	}

@@ -1357,6 +1453,8 @@ static const struct {
	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
	{"wmi_send",		  S_IWUSR,	&fops_wmi},
	{"back",	S_IRUGO | S_IWUSR,	&fops_back},
	{"pmccfg",	S_IRUGO | S_IWUSR,	&fops_pmccfg},
	{"pmcdata",	S_IRUGO,		&fops_pmcdata},
	{"temp",	S_IRUGO,		&fops_temp},
	{"freq",	S_IRUGO,		&fops_freq},
	{"link",	S_IRUGO,		&fops_link},
@@ -1405,6 +1503,7 @@ static const struct dbg_off dbg_wil_off[] = {
	WIL_FIELD(fw_version,	S_IRUGO,		doff_u32),
	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
	WIL_FIELD(ap_isolate,	S_IRUGO,		doff_u32),
	{},
};

@@ -1433,6 +1532,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
	if (IS_ERR_OR_NULL(dbg))
		return -ENODEV;

	wil_pmc_init(wil);

	wil6210_debugfs_init_files(wil, dbg);
	wil6210_debugfs_init_isr(wil, dbg);
	wil6210_debugfs_init_blobs(wil, dbg);
@@ -1452,4 +1553,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
{
	debugfs_remove_recursive(wil->debug);
	wil->debug = NULL;

	/* free pmc memory without sending command to fw, as it will
	 * be reset on the way down anyway
	 */
	wil_pmc_free(wil, false);
}
+60 −3
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10

bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");

bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
@@ -68,6 +72,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value.");

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

static int ring_order_set(const char *val, const struct kernel_param *kp)
{
@@ -95,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO);
MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO);
MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order");
module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO);
MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order");

#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
@@ -145,7 +152,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);

	sta->data_port_open = false;
	if (sta->status != wil_sta_unused) {
		if (!from_event)
			wmi_disconnect_sta(wil, sta->addr, reason_code);
@@ -216,6 +222,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_bcast_fini(wil);
		netif_tx_stop_all_queues(ndev);
		netif_carrier_off(ndev);

@@ -360,6 +367,36 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
	return -EINVAL;
}

int wil_bcast_init(struct wil6210_priv *wil)
{
	int ri = wil->bcast_vring, rc;

	if ((ri >= 0) && wil->vring_tx[ri].va)
		return 0;

	ri = wil_find_free_vring(wil);
	if (ri < 0)
		return ri;

	wil->bcast_vring = ri;
	rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
	if (rc)
		wil->bcast_vring = -1;

	return rc;
}

void wil_bcast_fini(struct wil6210_priv *wil)
{
	int ri = wil->bcast_vring;

	if (ri < 0)
		return;

	wil->bcast_vring = -1;
	wil_vring_fini_tx(wil, ri);
}

static void wil_connect_worker(struct work_struct *work)
{
	int rc;
@@ -407,6 +444,7 @@ int wil_priv_init(struct wil6210_priv *wil)
	init_completion(&wil->wmi_call);

	wil->pending_connect_cid = -1;
	wil->bcast_vring = -1;
	setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
	setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);

@@ -515,7 +553,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
static int wil_target_reset(struct wil6210_priv *wil)
{
	int delay = 0;
	u32 x;
	u32 x, x1 = 0;

	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);

@@ -570,12 +608,16 @@ static int wil_target_reset(struct wil6210_priv *wil)
	do {
		msleep(RST_DELAY);
		x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
		if (x1 != x) {
			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
			x1 = x;
		}
		if (delay++ > RST_COUNT) {
			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
				x);
			return -ETIME;
		}
	} while (!(x & BIT_BL_READY));
	} while (x != BIT_BL_READY);

	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

@@ -654,8 +696,20 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
	WARN_ON(!mutex_is_locked(&wil->mutex));
	WARN_ON(test_bit(wil_status_napi_en, wil->status));

	if (debug_fw) {
		static const u8 mac[ETH_ALEN] = {
			0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
		};
		struct net_device *ndev = wil_to_ndev(wil);

		ether_addr_copy(ndev->perm_addr, mac);
		ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
		return 0;
	}

	cancel_work_sync(&wil->disconnect_worker);
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
	wil_bcast_fini(wil);

	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
@@ -714,6 +768,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)

	/* init after reset */
	wil->pending_connect_cid = -1;
	wil->ap_isolate = 0;
	reinit_completion(&wil->wmi_ready);
	reinit_completion(&wil->wmi_call);

@@ -723,6 +778,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)

		/* we just started MAC, wait for FW ready */
		rc = wil_wait_for_fw_ready(wil);
		if (rc == 0) /* check FW is responsive */
			rc = wmi_echo(wil);
	}

	return rc;
+7 −2
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev)

	wil_dbg_misc(wil, "%s()\n", __func__);

	if (debug_fw) {
		wil_err(wil, "%s() while in debug_fw mode\n", __func__);
		return -EINVAL;
	}

	return wil_up(wil);
}

@@ -82,7 +87,7 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
	wil_rx_handle(wil, &quota);
	done = budget - quota;

	if (done <= 1) { /* burst ends - only one packet processed */
	if (done < budget) {
		napi_complete(napi);
		wil6210_unmask_irq_rx(wil);
		wil_dbg_txrx(wil, "NAPI RX complete\n");
@@ -110,7 +115,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
		tx_done += wil_tx_complete(wil, i);
	}

	if (tx_done <= 1) { /* burst ends - only one packet processed */
	if (tx_done < budget) {
		napi_complete(napi);
		wil6210_unmask_irq_tx(wil);
		wil_dbg_txrx(wil, "NAPI TX complete\n");
Loading