main.c 24.4 KB
Newer Older
1
/*
2
 * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <linux/moduleparam.h>
#include <linux/if_arp.h>
19
#include <linux/etherdevice.h>
20 21

#include "wil6210.h"
V
Vladimir Kondratiev 已提交
22
#include "txrx.h"
23 24 25 26
#include "wmi.h"

#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
27

V
Vladimir Kondratiev 已提交
28 29 30 31
bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");

32
bool no_fw_recovery;
V
Vladimir Kondratiev 已提交
33
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
34
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
V
Vladimir Kondratiev 已提交
35

36 37 38 39 40 41 42
/* if not set via modparam, will be set to default value of 1/8 of
 * rx ring size during init flow
 */
unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
MODULE_PARM_DESC(rx_ring_overflow_thrsh,
		 " RX ring overflow threshold in descriptors.");
V
Vladimir Kondratiev 已提交
43

44 45 46
/* We allow allocation of more than 1 page buffers to support large packets.
 * It is suboptimal behavior performance wise in case MTU above page size.
 */
47
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
48 49 50 51 52 53 54 55 56 57 58
static int mtu_max_set(const char *val, const struct kernel_param *kp)
{
	int ret;

	/* sets mtu_max directly. no need to restore it in case of
	 * illegal value since we assume this will fail insmod
	 */
	ret = param_set_uint(val, kp);
	if (ret)
		return ret;

59
	if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
60 61 62 63 64 65 66 67 68 69 70 71 72
		ret = -EINVAL;

	return ret;
}

static struct kernel_param_ops mtu_max_ops = {
	.set = mtu_max_set,
	.get = param_get_uint,
};

module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
MODULE_PARM_DESC(mtu_max, " Max MTU value.");

73 74
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
75
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

static int ring_order_set(const char *val, const struct kernel_param *kp)
{
	int ret;
	uint x;

	ret = kstrtouint(val, 0, &x);
	if (ret)
		return ret;

	if ((x < WIL_RING_SIZE_ORDER_MIN) || (x > WIL_RING_SIZE_ORDER_MAX))
		return -EINVAL;

	*((uint *)kp->arg) = x;

	return 0;
}

static struct kernel_param_ops ring_order_ops = {
	.set = ring_order_set,
	.get = param_get_uint,
};

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");

104 105 106
#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 */

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/*
 * Due to a hardware issue,
 * one has to read/write to/from NIC in 32-bit chunks;
 * regular memcpy_fromio and siblings will
 * not work on 64-bit platform - it uses 64-bit transactions
 *
 * Force 32-bit transactions to enable NIC on 64-bit platforms
 *
 * To avoid byte swap on big endian host, __raw_{read|write}l
 * should be used - {read|write}l would swap bytes to provide
 * little endian on PCI value in host endianness.
 */
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
			  size_t count)
{
	u32 *d = dst;
	const volatile u32 __iomem *s = src;

	/* size_t is unsigned, if (count%4 != 0) it will wrap */
	for (count += 4; count > 4; count -= 4)
		*d++ = __raw_readl(s++);
}

void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
			size_t count)
{
	volatile u32 __iomem *d = dst;
	const u32 *s = src;

	for (count += 4; count > 4; count -= 4)
		__raw_writel(*s++, d++);
}

140
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
141
			       u16 reason_code, bool from_event)
142
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
143 144
{
	uint i;
145 146
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
147
	struct wil_sta_info *sta = &wil->sta[cid];
148

149
	might_sleep();
150 151
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);
152

153
	sta->data_port_open = false;
154
	if (sta->status != wil_sta_unused) {
155
		if (!from_event)
156
			wmi_disconnect_sta(wil, sta->addr, reason_code);
157

158 159 160 161 162 163 164 165 166
		switch (wdev->iftype) {
		case NL80211_IFTYPE_AP:
		case NL80211_IFTYPE_P2P_GO:
			/* AP-like interface */
			cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
			break;
		default:
			break;
		}
167 168 169
		sta->status = wil_sta_unused;
	}

170
	for (i = 0; i < WIL_STA_TID_NUM; i++) {
171 172
		struct wil_tid_ampdu_rx *r;

173
		spin_lock_bh(&sta->tid_rx_lock);
174 175

		r = sta->tid_rx[i];
176 177
		sta->tid_rx[i] = NULL;
		wil_tid_ampdu_rx_free(wil, r);
178

179
		spin_unlock_bh(&sta->tid_rx_lock);
180 181 182 183 184 185 186 187
	}
	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
		if (wil->vring2cid_tid[i][0] == cid)
			wil_vring_fini_tx(wil, i);
	}
	memset(&sta->stats, 0, sizeof(sta->stats));
}

188
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
189
				u16 reason_code, bool from_event)
190
{
191
	int cid = -ENOENT;
192
	struct net_device *ndev = wil_to_ndev(wil);
193 194 195
	struct wireless_dev *wdev = wil->wdev;

	might_sleep();
196 197 198 199 200 201 202 203 204 205 206 207 208
	wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
		     reason_code, from_event ? "+" : "-");

	/* Cases are:
	 * - disconnect single STA, still connected
	 * - disconnect single STA, already disconnected
	 * - disconnect all
	 *
	 * For "disconnect all", there are 2 options:
	 * - bssid == NULL
	 * - bssid is our MAC address
	 */
	if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) {
209
		cid = wil_find_cid(wil, bssid);
210 211 212 213 214 215
		wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
			     bssid, cid, reason_code);
		if (cid >= 0) /* disconnect 1 peer */
			wil_disconnect_cid(wil, cid, reason_code, from_event);
	} else { /* all */
		wil_dbg_misc(wil, "Disconnect all\n");
216
		for (cid = 0; cid < WIL6210_MAX_CID; cid++)
217
			wil_disconnect_cid(wil, cid, reason_code, from_event);
218
	}
219 220 221 222 223

	/* link state */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
224
		wil_bcast_fini(wil);
225 226 227
		netif_tx_stop_all_queues(ndev);
		netif_carrier_off(ndev);

228 229
		if (test_bit(wil_status_fwconnected, wil->status)) {
			clear_bit(wil_status_fwconnected, wil->status);
230
			cfg80211_disconnected(ndev, reason_code,
231
					      NULL, 0, GFP_KERNEL);
232
		} else if (test_bit(wil_status_fwconnecting, wil->status)) {
233 234 235 236
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
		}
237
		clear_bit(wil_status_fwconnecting, wil->status);
238 239 240
		break;
	default:
		break;
241 242 243 244 245 246 247 248
	}
}

static void wil_disconnect_worker(struct work_struct *work)
{
	struct wil6210_priv *wil = container_of(work,
			struct wil6210_priv, disconnect_worker);

249
	mutex_lock(&wil->mutex);
250
	_wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false);
251
	mutex_unlock(&wil->mutex);
252 253 254 255 256 257
}

static void wil_connect_timer_fn(ulong x)
{
	struct wil6210_priv *wil = (void *)x;

258
	wil_dbg_misc(wil, "Connect timeout\n");
259 260 261 262 263 264 265

	/* reschedule to thread context - disconnect won't
	 * run from atomic context
	 */
	schedule_work(&wil->disconnect_worker);
}

266 267 268 269
static void wil_scan_timer_fn(ulong x)
{
	struct wil6210_priv *wil = (void *)x;

270
	clear_bit(wil_status_fwready, wil->status);
271
	wil_err(wil, "Scan timeout detected, start fw error recovery\n");
272
	wil->recovery_state = fw_recovery_pending;
273 274 275
	schedule_work(&wil->fw_error_worker);
}

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
static int wil_wait_for_recovery(struct wil6210_priv *wil)
{
	if (wait_event_interruptible(wil->wq, wil->recovery_state !=
				     fw_recovery_pending)) {
		wil_err(wil, "Interrupt, canceling recovery\n");
		return -ERESTARTSYS;
	}
	if (wil->recovery_state != fw_recovery_running) {
		wil_info(wil, "Recovery cancelled\n");
		return -EINTR;
	}
	wil_info(wil, "Proceed with recovery\n");
	return 0;
}

void wil_set_recovery_state(struct wil6210_priv *wil, int state)
{
	wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__,
		     wil->recovery_state, state);

	wil->recovery_state = state;
	wake_up_interruptible(&wil->wq);
}

V
Vladimir Kondratiev 已提交
300 301
static void wil_fw_error_worker(struct work_struct *work)
{
302 303
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
V
Vladimir Kondratiev 已提交
304 305 306 307
	struct wireless_dev *wdev = wil->wdev;

	wil_dbg_misc(wil, "fw error worker\n");

308 309 310 311 312
	if (!netif_running(wil_to_ndev(wil))) {
		wil_info(wil, "No recovery - interface is down\n");
		return;
	}

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
	 * passed since last recovery attempt
	 */
	if (time_is_after_jiffies(wil->last_fw_recovery +
				  WIL6210_FW_RECOVERY_TO))
		wil->recovery_count++;
	else
		wil->recovery_count = 1; /* fw was alive for a long time */

	if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) {
		wil_err(wil, "too many recovery attempts (%d), giving up\n",
			wil->recovery_count);
		return;
	}

	wil->last_fw_recovery = jiffies;

330
	mutex_lock(&wil->mutex);
V
Vladimir Kondratiev 已提交
331 332 333 334
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_MONITOR:
335
		wil_info(wil, "fw error recovery requested (try %d)...\n",
336
			 wil->recovery_count);
337 338 339 340 341
		if (!no_fw_recovery)
			wil->recovery_state = fw_recovery_running;
		if (0 != wil_wait_for_recovery(wil))
			break;

342 343
		__wil_down(wil);
		__wil_up(wil);
V
Vladimir Kondratiev 已提交
344 345 346
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
347
		wil_info(wil, "No recovery for AP-like interface\n");
V
Vladimir Kondratiev 已提交
348 349 350
		/* recovery in these modes is done by upper layers */
		break;
	default:
351 352
		wil_err(wil, "No recovery - unknown interface type %d\n",
			wdev->iftype);
V
Vladimir Kondratiev 已提交
353 354
		break;
	}
355
	mutex_unlock(&wil->mutex);
V
Vladimir Kondratiev 已提交
356 357
}

358 359 360
static int wil_find_free_vring(struct wil6210_priv *wil)
{
	int i;
361

362 363 364 365 366 367 368
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
		if (!wil->vring_tx[i].va)
			return i;
	}
	return -EINVAL;
}

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
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;

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

	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);
}

398 399 400 401 402
static void wil_connect_worker(struct work_struct *work)
{
	int rc;
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						connect_worker);
403 404
	struct net_device *ndev = wil_to_ndev(wil);

405
	int cid = wil->pending_connect_cid;
406
	int ringid = wil_find_free_vring(wil);
407 408 409 410 411 412 413 414

	if (cid < 0) {
		wil_err(wil, "No connection pending\n");
		return;
	}

	wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);

415
	rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
416
	wil->pending_connect_cid = -1;
417 418
	if (rc == 0) {
		wil->sta[cid].status = wil_sta_connected;
419
		netif_tx_wake_all_queues(ndev);
420 421 422
	} else {
		wil->sta[cid].status = wil_sta_unused;
	}
423 424
}

425 426
int wil_priv_init(struct wil6210_priv *wil)
{
427 428
	uint i;

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

431
	memset(wil->sta, 0, sizeof(wil->sta));
432 433
	for (i = 0; i < WIL6210_MAX_CID; i++)
		spin_lock_init(&wil->sta[i].tid_rx_lock);
434

435 436
	mutex_init(&wil->mutex);
	mutex_init(&wil->wmi_mutex);
V
Vladimir Kondratiev 已提交
437
	mutex_init(&wil->back_rx_mutex);
438
	mutex_init(&wil->back_tx_mutex);
439
	mutex_init(&wil->probe_client_mutex);
440 441

	init_completion(&wil->wmi_ready);
442
	init_completion(&wil->wmi_call);
443 444

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

449
	INIT_WORK(&wil->connect_worker, wil_connect_worker);
450 451
	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
V
Vladimir Kondratiev 已提交
452
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
V
Vladimir Kondratiev 已提交
453
	INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
454
	INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
455
	INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
456 457

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
V
Vladimir Kondratiev 已提交
458
	INIT_LIST_HEAD(&wil->back_rx_pending);
459
	INIT_LIST_HEAD(&wil->back_tx_pending);
460
	INIT_LIST_HEAD(&wil->probe_client_pending);
461
	spin_lock_init(&wil->wmi_ev_lock);
462
	init_waitqueue_head(&wil->wq);
463

V
Vladimir Kondratiev 已提交
464
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
465 466 467
	if (!wil->wmi_wq)
		return -EAGAIN;

V
Vladimir Kondratiev 已提交
468 469 470
	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
	if (!wil->wq_service)
		goto out_wmi_wq;
471

472
	wil->last_fw_recovery = jiffies;
473 474 475 476
	wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
	wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
	wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
	wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;
477

478 479
	if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
		rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
480
	return 0;
V
Vladimir Kondratiev 已提交
481 482 483 484 485

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
486 487
}

488 489 490 491
/**
 * wil6210_disconnect - disconnect one connection
 * @wil: driver context
 * @bssid: peer to disconnect, NULL to disconnect all
492
 * @reason_code: Reason code for the Disassociation frame
493 494 495 496 497 498
 * @from_event: whether is invoked from FW event handler
 *
 * Disconnect and release associated resources. If invoked not from the
 * FW event handler, issue WMI command(s) to trigger MAC disconnect.
 */
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
499
			u16 reason_code, bool from_event)
500
{
501 502
	wil_dbg_misc(wil, "%s()\n", __func__);

503
	del_timer_sync(&wil->connect_timer);
504
	_wil6210_disconnect(wil, bssid, reason_code, from_event);
505 506 507 508
}

void wil_priv_deinit(struct wil6210_priv *wil)
{
509 510
	wil_dbg_misc(wil, "%s()\n", __func__);

511
	wil_set_recovery_state(wil, fw_recovery_idle);
512
	del_timer_sync(&wil->scan_timer);
513
	cancel_work_sync(&wil->disconnect_worker);
V
Vladimir Kondratiev 已提交
514
	cancel_work_sync(&wil->fw_error_worker);
515
	mutex_lock(&wil->mutex);
516
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
517
	mutex_unlock(&wil->mutex);
518
	wmi_event_flush(wil);
V
Vladimir Kondratiev 已提交
519 520
	wil_back_rx_flush(wil);
	cancel_work_sync(&wil->back_rx_worker);
521 522
	wil_back_tx_flush(wil);
	cancel_work_sync(&wil->back_tx_worker);
523 524
	wil_probe_client_flush(wil);
	cancel_work_sync(&wil->probe_client_worker);
V
Vladimir Kondratiev 已提交
525
	destroy_workqueue(wil->wq_service);
526 527 528
	destroy_workqueue(wil->wmi_wq);
}

V
Vladimir Kondratiev 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
/* target operations */
/* register read */
#define R(a) ioread32(wil->csr + HOSTADDR(a))
/* register write. wmb() to make sure it is completed */
#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
/* register set = read, OR, write */
#define S(a, v) W(a, R(a) | v)
/* register clear = read, AND with inverted, write */
#define C(a, v) W(a, R(a) & ~v)

static inline void wil_halt_cpu(struct wil6210_priv *wil)
{
	W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
	W(RGF_USER_MAC_CPU_0,  BIT_USER_MAC_CPU_MAN_RST);
}

static inline void wil_release_cpu(struct wil6210_priv *wil)
{
	/* Start CPU */
	W(RGF_USER_USER_CPU_0, 1);
}

551
static int wil_target_reset(struct wil6210_priv *wil)
552
{
V
Vladimir Kondratiev 已提交
553
	int delay = 0;
V
Vladimir Kondratiev 已提交
554
	u32 x;
555

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

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
560 561 562 563
	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);

	wil_halt_cpu(wil);
564

V
Vladimir Kondratiev 已提交
565 566
	/* clear all boot loader "ready" bits */
	W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0);
V
Vladimir Kondratiev 已提交
567 568 569
	/* Clear Fw Download notification */
	C(RGF_USER_USAGE_6, BIT(0));

570 571 572 573 574 575 576 577
	S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
	/* XTAL stabilization should take about 3ms */
	usleep_range(5000, 7000);
	x = R(RGF_CAF_PLL_LOCK_STATUS);
	if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {
		wil_err(wil, "Xtal stabilization timeout\n"
			"RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);
		return -ETIME;
578
	}
579 580 581 582 583 584 585
	/* switch 10k to XTAL*/
	C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);
	/* 40 MHz */
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL);

	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
586

587 588
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
589
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
V
Vladimir Kondratiev 已提交
590
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
591

592 593
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
594

595 596 597 598 599
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

600 601
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */
602

603 604
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

V
Vladimir Kondratiev 已提交
605
	/* wait until device ready. typical time is 20..80 msec */
606
	do {
607
		msleep(RST_DELAY);
V
Vladimir Kondratiev 已提交
608
		x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
609
		if (delay++ > RST_COUNT) {
V
Vladimir Kondratiev 已提交
610
			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
V
Vladimir Kondratiev 已提交
611
				x);
612
			return -ETIME;
613
		}
V
Vladimir Kondratiev 已提交
614
	} while (!(x & BIT_BL_READY));
615

616 617
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

618 619 620 621
	/* enable fix for HW bug related to the SA/DA swap in AP Rx */
	S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN |
	  BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);

622
	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
623
	return 0;
V
Vladimir Kondratiev 已提交
624
}
625 626 627 628 629 630 631 632 633 634

void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
{
	le32_to_cpus(&r->base);
	le16_to_cpus(&r->entry_size);
	le16_to_cpus(&r->size);
	le32_to_cpus(&r->tail);
	le32_to_cpus(&r->head);
}

V
Vladimir Kondratiev 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
static int wil_get_bl_info(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct RGF_BL bl;

	wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl));
	le32_to_cpus(&bl.ready);
	le32_to_cpus(&bl.version);
	le32_to_cpus(&bl.rf_type);
	le32_to_cpus(&bl.baseband_type);

	if (!is_valid_ether_addr(bl.mac_address)) {
		wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address);
		return -EINVAL;
	}

	ether_addr_copy(ndev->perm_addr, bl.mac_address);
	if (!is_valid_ether_addr(ndev->dev_addr))
		ether_addr_copy(ndev->dev_addr, bl.mac_address);
	wil_info(wil,
		 "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n",
		 bl.version, bl.mac_address, bl.rf_type, bl.baseband_type);

	return 0;
}

661 662 663 664
static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
	ulong to = msecs_to_jiffies(1000);
	ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
665

666 667 668 669
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
670 671
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
672 673 674 675 676 677 678 679 680
	}
	return 0;
}

/*
 * We reset all the structures, and we reset the UMAC.
 * After calling this routine, you're expected to reload
 * the firmware.
 */
V
Vladimir Kondratiev 已提交
681
int wil_reset(struct wil6210_priv *wil, bool load_fw)
682 683 684
{
	int rc;

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

687 688 689
	if (wil->hw_version == HW_VER_UNKNOWN)
		return -ENODEV;

690
	WARN_ON(!mutex_is_locked(&wil->mutex));
691
	WARN_ON(test_bit(wil_status_napi_en, wil->status));
692

V
Vladimir Kondratiev 已提交
693 694 695 696 697 698 699 700 701 702 703
	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;
	}

704
	cancel_work_sync(&wil->disconnect_worker);
705
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
706
	wil_bcast_fini(wil);
707

708 709
	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
710

V
Vladimir Kondratiev 已提交
711 712 713
	if (wil->scan_request) {
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
714
		del_timer_sync(&wil->scan_timer);
V
Vladimir Kondratiev 已提交
715 716 717 718
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

719
	wil_mask_irq(wil);
720

721 722
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
723
	flush_workqueue(wil->wq_service);
724
	flush_workqueue(wil->wmi_wq);
725

726
	rc = wil_target_reset(wil);
727
	wil_rx_fini(wil);
728 729 730
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
731 732 733 734 735 736 737 738
	rc = wil_get_bl_info(wil);
	if (rc)
		return rc;

	if (load_fw) {
		wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME,
			 WIL_FW2_NAME);

V
Vladimir Kondratiev 已提交
739 740 741 742 743
		wil_halt_cpu(wil);
		/* Loading f/w from the file */
		rc = wil_request_firmware(wil, WIL_FW_NAME);
		if (rc)
			return rc;
V
Vladimir Kondratiev 已提交
744 745 746 747 748 749
		rc = wil_request_firmware(wil, WIL_FW2_NAME);
		if (rc)
			return rc;

		/* Mark FW as loaded from host */
		S(RGF_USER_USAGE_6, 1);
V
Vladimir Kondratiev 已提交
750

V
Vladimir Kondratiev 已提交
751 752 753
		/* clear any interrupts which on-card-firmware
		 * may have set
		 */
V
Vladimir Kondratiev 已提交
754
		wil6210_clear_irq(wil);
V
Vladimir Kondratiev 已提交
755 756 757 758 759
		/* CAF_ICR - clear and mask */
		/* it is W1C, clear by writing back same value */
		S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
		W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);

V
Vladimir Kondratiev 已提交
760 761
		wil_release_cpu(wil);
	}
762

763 764
	/* init after reset */
	wil->pending_connect_cid = -1;
765
	wil->ap_isolate = 0;
766
	reinit_completion(&wil->wmi_ready);
767
	reinit_completion(&wil->wmi_call);
768

V
Vladimir Kondratiev 已提交
769 770 771
	if (load_fw) {
		wil_configure_interrupt_moderation(wil);
		wil_unmask_irq(wil);
772

V
Vladimir Kondratiev 已提交
773 774
		/* we just started MAC, wait for FW ready */
		rc = wil_wait_for_fw_ready(wil);
775 776
		if (rc == 0) /* check FW is responsive */
			rc = wmi_echo(wil);
V
Vladimir Kondratiev 已提交
777
	}
778 779 780 781

	return rc;
}

V
Vladimir Kondratiev 已提交
782 783 784 785 786
#undef R
#undef W
#undef S
#undef C

V
Vladimir Kondratiev 已提交
787 788 789
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
790
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
791 792
	schedule_work(&wil->fw_error_worker);
}
793

794
int __wil_up(struct wil6210_priv *wil)
795 796 797 798 799
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

800 801
	WARN_ON(!mutex_is_locked(&wil->mutex));

V
Vladimir Kondratiev 已提交
802
	rc = wil_reset(wil, true);
803 804 805
	if (rc)
		return rc;

806
	/* Rx VRING. After MAC and beacon */
807
	rc = wil_rx_init(wil, 1 << rx_ring_order);
808 809 810
	if (rc)
		return rc;

811 812
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
813
		wil_dbg_misc(wil, "type: STATION\n");
814 815 816
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
817
		wil_dbg_misc(wil, "type: AP\n");
818 819 820
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
821
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
822 823 824
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
825
		wil_dbg_misc(wil, "type: P2P_GO\n");
826 827 828
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
829
		wil_dbg_misc(wil, "type: Monitor\n");
830 831 832 833 834 835 836 837 838 839
		ndev->type = ARPHRD_IEEE80211_RADIOTAP;
		/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
		break;
	default:
		return -EOPNOTSUPP;
	}

	/* MAC address - pre-requisite for other commands */
	wmi_set_mac_address(wil, ndev->dev_addr);

840
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
841 842
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
843
	set_bit(wil_status_napi_en, wil->status);
V
Vladimir Kondratiev 已提交
844

845 846 847 848
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

849 850 851 852 853 854 855
	return 0;
}

int wil_up(struct wil6210_priv *wil)
{
	int rc;

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

858 859 860 861 862 863 864
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

865
int __wil_down(struct wil6210_priv *wil)
866
{
867 868 869
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

870 871
	WARN_ON(!mutex_is_locked(&wil->mutex));

872 873 874
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

875
	wil_disable_irq(wil);
876
	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
877 878 879 880 881
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
		wil_dbg_misc(wil, "NAPI disable\n");
	}
	wil_enable_irq(wil);
V
Vladimir Kondratiev 已提交
882

883
	if (wil->scan_request) {
884 885
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
886
		del_timer_sync(&wil->scan_timer);
887 888 889 890
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

891 892
	if (test_bit(wil_status_fwconnected, wil->status) ||
	    test_bit(wil_status_fwconnecting, wil->status))
893 894 895 896 897
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
898 899
		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
			   !test_bit(wil_status_fwconnecting, wil->status);
900 901 902 903 904 905 906 907 908
		if (idle)
			break;
		msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
	}
	mutex_lock(&wil->mutex);

	if (!iter)
		wil_err(wil, "timeout waiting for idle FW/HW\n");

V
Vladimir Kondratiev 已提交
909
	wil_reset(wil, false);
910 911 912 913 914 915 916 917

	return 0;
}

int wil_down(struct wil6210_priv *wil)
{
	int rc;

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

920
	wil_set_recovery_state(wil, fw_recovery_idle);
921 922 923 924 925 926
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
927 928 929 930 931 932 933 934

int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
{
	int i;
	int rc = -ENOENT;

	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
		if ((wil->sta[i].status != wil_sta_unused) &&
935
		    ether_addr_equal(wil->sta[i].addr, mac)) {
936 937 938 939 940 941 942
			rc = i;
			break;
		}
	}

	return rc;
}