main.c 24.5 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

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

157 158 159 160 161 162 163 164 165
		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;
		}
166 167 168
		sta->status = wil_sta_unused;
	}

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

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

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

178
		spin_unlock_bh(&sta->tid_rx_lock);
179 180 181 182 183 184 185 186
	}
	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));
}

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

	might_sleep();
195 196 197 198 199 200 201 202 203 204 205 206 207
	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)) {
208
		cid = wil_find_cid(wil, bssid);
209 210 211 212 213 214
		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");
215
		for (cid = 0; cid < WIL6210_MAX_CID; cid++)
216
			wil_disconnect_cid(wil, cid, reason_code, from_event);
217
	}
218 219 220 221 222

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

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

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

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

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

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

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

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

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

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
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 已提交
299 300
static void wil_fw_error_worker(struct work_struct *work)
{
301 302
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
V
Vladimir Kondratiev 已提交
303 304 305 306
	struct wireless_dev *wdev = wil->wdev;

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

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

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
	/* 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;

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

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

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

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

368 369 370 371 372 373 374 375 376 377 378
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;

379
	wil->bcast_vring = ri;
380
	rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
381 382
	if (rc)
		wil->bcast_vring = -1;
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397

	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;
554
	u32 x, x1 = 0;
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 610 611 612
		if (x1 != x) {
			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
			x1 = x;
		}
613
		if (delay++ > RST_COUNT) {
V
Vladimir Kondratiev 已提交
614
			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
V
Vladimir Kondratiev 已提交
615
				x);
616
			return -ETIME;
617
		}
618
	} while (x != BIT_BL_READY);
619

620 621
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

622 623 624 625
	/* 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);

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

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 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
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;
}

665 666 667 668
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);
669

670 671 672 673
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
674 675
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
676 677 678 679 680 681 682 683 684
	}
	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 已提交
685
int wil_reset(struct wil6210_priv *wil, bool load_fw)
686 687 688
{
	int rc;

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

691 692 693
	if (wil->hw_version == HW_VER_UNKNOWN)
		return -ENODEV;

694
	WARN_ON(!mutex_is_locked(&wil->mutex));
695
	WARN_ON(test_bit(wil_status_napi_en, wil->status));
696

V
Vladimir Kondratiev 已提交
697 698 699 700 701 702 703 704 705 706 707
	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;
	}

708
	cancel_work_sync(&wil->disconnect_worker);
709
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
710
	wil_bcast_fini(wil);
711

712 713
	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
714

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

723
	wil_mask_irq(wil);
724

725 726
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
727
	flush_workqueue(wil->wq_service);
728
	flush_workqueue(wil->wmi_wq);
729

730
	rc = wil_target_reset(wil);
731
	wil_rx_fini(wil);
732 733 734
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
735 736 737 738 739 740 741 742
	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 已提交
743 744 745 746 747
		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 已提交
748 749 750 751 752 753
		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 已提交
754

V
Vladimir Kondratiev 已提交
755 756 757
		/* clear any interrupts which on-card-firmware
		 * may have set
		 */
V
Vladimir Kondratiev 已提交
758
		wil6210_clear_irq(wil);
V
Vladimir Kondratiev 已提交
759 760 761 762 763
		/* 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 已提交
764 765
		wil_release_cpu(wil);
	}
766

767 768
	/* init after reset */
	wil->pending_connect_cid = -1;
769
	wil->ap_isolate = 0;
770
	reinit_completion(&wil->wmi_ready);
771
	reinit_completion(&wil->wmi_call);
772

V
Vladimir Kondratiev 已提交
773 774 775
	if (load_fw) {
		wil_configure_interrupt_moderation(wil);
		wil_unmask_irq(wil);
776

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

	return rc;
}

V
Vladimir Kondratiev 已提交
786 787 788 789 790
#undef R
#undef W
#undef S
#undef C

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

798
int __wil_up(struct wil6210_priv *wil)
799 800 801 802 803
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

804 805
	WARN_ON(!mutex_is_locked(&wil->mutex));

V
Vladimir Kondratiev 已提交
806
	rc = wil_reset(wil, true);
807 808 809
	if (rc)
		return rc;

810
	/* Rx VRING. After MAC and beacon */
811
	rc = wil_rx_init(wil, 1 << rx_ring_order);
812 813 814
	if (rc)
		return rc;

815 816
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
817
		wil_dbg_misc(wil, "type: STATION\n");
818 819 820
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
821
		wil_dbg_misc(wil, "type: AP\n");
822 823 824
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
825
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
826 827 828
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
829
		wil_dbg_misc(wil, "type: P2P_GO\n");
830 831 832
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
833
		wil_dbg_misc(wil, "type: Monitor\n");
834 835 836 837 838 839 840 841 842 843
		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);

844
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
845 846
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
847
	set_bit(wil_status_napi_en, wil->status);
V
Vladimir Kondratiev 已提交
848

849 850 851 852
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

853 854 855 856 857 858 859
	return 0;
}

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

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

862 863 864 865 866 867 868
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

869
int __wil_down(struct wil6210_priv *wil)
870
{
871 872 873
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

874 875
	WARN_ON(!mutex_is_locked(&wil->mutex));

876 877 878
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

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

887
	if (wil->scan_request) {
888 889
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
890
		del_timer_sync(&wil->scan_timer);
891 892 893 894
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

895 896
	if (test_bit(wil_status_fwconnected, wil->status) ||
	    test_bit(wil_status_fwconnecting, wil->status))
897 898 899 900 901
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
902 903
		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
			   !test_bit(wil_status_fwconnecting, wil->status);
904 905 906 907 908 909 910 911 912
		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 已提交
913
	wil_reset(wil, false);
914 915 916 917 918 919 920 921

	return 0;
}

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

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

924
	wil_set_recovery_state(wil, fw_recovery_idle);
925 926 927 928 929 930
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
931 932 933 934 935 936 937 938

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) &&
939
		    ether_addr_equal(wil->sta[i].addr, mac)) {
940 941 942 943 944 945 946
			rc = i;
			break;
		}
	}

	return rc;
}