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

28
bool no_fw_recovery;
V
Vladimir Kondratiev 已提交
29
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
30
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
V
Vladimir Kondratiev 已提交
31

32 33 34 35 36 37 38
/* 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 已提交
39

40 41 42
/* 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.
 */
43
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
44 45 46 47 48 49 50 51 52 53 54
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;

55
	if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
56 57 58 59 60
		ret = -EINVAL;

	return ret;
}

61
static const struct kernel_param_ops mtu_max_ops = {
62 63 64 65 66 67 68
	.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.");

69 70
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
71
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

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

90
static const struct kernel_param_ops ring_order_ops = {
91 92 93 94 95 96 97 98 99
	.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");

100 101 102
#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 */

103 104 105 106 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
/*
 * 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++);
}

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

145
	might_sleep();
146 147
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);
148

149
	sta->data_port_open = false;
150
	if (sta->status != wil_sta_unused) {
151
		if (!from_event)
152
			wmi_disconnect_sta(wil, sta->addr, reason_code);
153

154 155 156 157 158 159 160 161 162
		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;
		}
163 164 165
		sta->status = wil_sta_unused;
	}

166
	for (i = 0; i < WIL_STA_TID_NUM; i++) {
167 168
		struct wil_tid_ampdu_rx *r;

169
		spin_lock_bh(&sta->tid_rx_lock);
170 171

		r = sta->tid_rx[i];
172 173
		sta->tid_rx[i] = NULL;
		wil_tid_ampdu_rx_free(wil, r);
174

175
		spin_unlock_bh(&sta->tid_rx_lock);
176 177 178 179 180 181 182 183
	}
	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));
}

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

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

	/* link state */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
220
		wil_bcast_fini(wil);
221 222 223
		netif_tx_stop_all_queues(ndev);
		netif_carrier_off(ndev);

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

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

245
	mutex_lock(&wil->mutex);
246
	_wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false);
247
	mutex_unlock(&wil->mutex);
248 249 250 251 252 253
}

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

254
	wil_dbg_misc(wil, "Connect timeout\n");
255 256 257 258 259 260 261

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

262 263 264 265
static void wil_scan_timer_fn(ulong x)
{
	struct wil6210_priv *wil = (void *)x;

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

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

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

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

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

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

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

354 355 356
static int wil_find_free_vring(struct wil6210_priv *wil)
{
	int i;
357

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

365 366 367 368 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
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);
}

394 395 396 397 398
static void wil_connect_worker(struct work_struct *work)
{
	int rc;
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						connect_worker);
399 400
	struct net_device *ndev = wil_to_ndev(wil);

401
	int cid = wil->pending_connect_cid;
402
	int ringid = wil_find_free_vring(wil);
403 404 405 406 407 408 409 410

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

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

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

421 422
int wil_priv_init(struct wil6210_priv *wil)
{
423 424
	uint i;

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

427
	memset(wil->sta, 0, sizeof(wil->sta));
428 429
	for (i = 0; i < WIL6210_MAX_CID; i++)
		spin_lock_init(&wil->sta[i].tid_rx_lock);
430

431 432
	mutex_init(&wil->mutex);
	mutex_init(&wil->wmi_mutex);
V
Vladimir Kondratiev 已提交
433
	mutex_init(&wil->back_rx_mutex);
434
	mutex_init(&wil->back_tx_mutex);
435
	mutex_init(&wil->probe_client_mutex);
436 437

	init_completion(&wil->wmi_ready);
438
	init_completion(&wil->wmi_call);
439 440

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

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

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
V
Vladimir Kondratiev 已提交
454
	INIT_LIST_HEAD(&wil->back_rx_pending);
455
	INIT_LIST_HEAD(&wil->back_tx_pending);
456
	INIT_LIST_HEAD(&wil->probe_client_pending);
457
	spin_lock_init(&wil->wmi_ev_lock);
458
	init_waitqueue_head(&wil->wq);
459

V
Vladimir Kondratiev 已提交
460
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
461 462 463
	if (!wil->wmi_wq)
		return -EAGAIN;

V
Vladimir Kondratiev 已提交
464 465 466
	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
	if (!wil->wq_service)
		goto out_wmi_wq;
467

468
	wil->last_fw_recovery = jiffies;
469 470 471 472
	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;
473

474 475
	if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
		rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
476
	return 0;
V
Vladimir Kondratiev 已提交
477 478 479 480 481

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
482 483
}

484 485 486 487
/**
 * wil6210_disconnect - disconnect one connection
 * @wil: driver context
 * @bssid: peer to disconnect, NULL to disconnect all
488
 * @reason_code: Reason code for the Disassociation frame
489 490 491 492 493 494
 * @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,
495
			u16 reason_code, bool from_event)
496
{
497 498
	wil_dbg_misc(wil, "%s()\n", __func__);

499
	del_timer_sync(&wil->connect_timer);
500
	_wil6210_disconnect(wil, bssid, reason_code, from_event);
501 502 503 504
}

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

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

V
Vladimir Kondratiev 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
/* 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);
}

547
static int wil_target_reset(struct wil6210_priv *wil)
548
{
V
Vladimir Kondratiev 已提交
549
	int delay = 0;
V
Vladimir Kondratiev 已提交
550
	u32 x;
551

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

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
556 557 558 559
	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);
560

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

566 567 568 569 570 571 572 573
	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;
574
	}
575 576 577 578 579 580 581
	/* 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);
582

583 584
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
585
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
V
Vladimir Kondratiev 已提交
586
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
587

588 589
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
590

591 592 593 594 595
	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);

596 597
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */
598

599 600
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

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

612 613
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

614 615 616 617
	/* 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);

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

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 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
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;
}

657 658 659 660
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);
661

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

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

683 684 685
	if (wil->hw_version == HW_VER_UNKNOWN)
		return -ENODEV;

686
	WARN_ON(!mutex_is_locked(&wil->mutex));
687
	WARN_ON(test_bit(wil_status_napi_en, wil->status));
688 689

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

693 694
	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
695

V
Vladimir Kondratiev 已提交
696 697 698
	if (wil->scan_request) {
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
699
		del_timer_sync(&wil->scan_timer);
V
Vladimir Kondratiev 已提交
700 701 702 703
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

704
	wil_mask_irq(wil);
705

706 707
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
708
	flush_workqueue(wil->wq_service);
709
	flush_workqueue(wil->wmi_wq);
710

711
	rc = wil_target_reset(wil);
712
	wil_rx_fini(wil);
713 714 715
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
716 717 718 719 720 721 722 723
	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 已提交
724 725 726 727 728
		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 已提交
729 730 731 732 733 734
		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 已提交
735

V
Vladimir Kondratiev 已提交
736 737 738
		/* clear any interrupts which on-card-firmware
		 * may have set
		 */
V
Vladimir Kondratiev 已提交
739
		wil6210_clear_irq(wil);
V
Vladimir Kondratiev 已提交
740 741 742 743 744
		/* 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 已提交
745 746
		wil_release_cpu(wil);
	}
747

748 749
	/* init after reset */
	wil->pending_connect_cid = -1;
750
	wil->ap_isolate = 0;
751
	reinit_completion(&wil->wmi_ready);
752
	reinit_completion(&wil->wmi_call);
753

V
Vladimir Kondratiev 已提交
754 755 756
	if (load_fw) {
		wil_configure_interrupt_moderation(wil);
		wil_unmask_irq(wil);
757

V
Vladimir Kondratiev 已提交
758 759
		/* we just started MAC, wait for FW ready */
		rc = wil_wait_for_fw_ready(wil);
760 761
		if (rc == 0) /* check FW is responsive */
			rc = wmi_echo(wil);
V
Vladimir Kondratiev 已提交
762
	}
763 764 765 766

	return rc;
}

V
Vladimir Kondratiev 已提交
767 768 769 770 771
#undef R
#undef W
#undef S
#undef C

V
Vladimir Kondratiev 已提交
772 773 774
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
775
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
776 777
	schedule_work(&wil->fw_error_worker);
}
778

779
int __wil_up(struct wil6210_priv *wil)
780 781 782 783 784
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

785 786
	WARN_ON(!mutex_is_locked(&wil->mutex));

V
Vladimir Kondratiev 已提交
787
	rc = wil_reset(wil, true);
788 789 790
	if (rc)
		return rc;

791
	/* Rx VRING. After MAC and beacon */
792
	rc = wil_rx_init(wil, 1 << rx_ring_order);
793 794 795
	if (rc)
		return rc;

796 797
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
798
		wil_dbg_misc(wil, "type: STATION\n");
799 800 801
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
802
		wil_dbg_misc(wil, "type: AP\n");
803 804 805
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
806
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
807 808 809
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
810
		wil_dbg_misc(wil, "type: P2P_GO\n");
811 812 813
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
814
		wil_dbg_misc(wil, "type: Monitor\n");
815 816 817 818 819 820 821 822 823 824
		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);

825
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
826 827
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
828
	set_bit(wil_status_napi_en, wil->status);
V
Vladimir Kondratiev 已提交
829

830 831 832 833
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

834 835 836 837 838 839 840
	return 0;
}

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

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

843 844 845 846 847 848 849
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

850
int __wil_down(struct wil6210_priv *wil)
851
{
852 853 854
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

855 856
	WARN_ON(!mutex_is_locked(&wil->mutex));

857 858 859
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

860
	wil_disable_irq(wil);
861
	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
862 863 864 865 866
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
		wil_dbg_misc(wil, "NAPI disable\n");
	}
	wil_enable_irq(wil);
V
Vladimir Kondratiev 已提交
867

868
	if (wil->scan_request) {
869 870
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
871
		del_timer_sync(&wil->scan_timer);
872 873 874 875
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

876 877
	if (test_bit(wil_status_fwconnected, wil->status) ||
	    test_bit(wil_status_fwconnecting, wil->status))
878 879 880 881 882
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
883 884
		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
			   !test_bit(wil_status_fwconnecting, wil->status);
885 886 887 888 889 890 891 892 893
		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 已提交
894
	wil_reset(wil, false);
895 896 897 898 899 900 901 902

	return 0;
}

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

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

905
	wil_set_recovery_state(wil, fw_recovery_idle);
906 907 908 909 910 911
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
912 913 914 915 916 917 918 919

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) &&
920
		    ether_addr_equal(wil->sta[i].addr, mac)) {
921 922 923 924 925 926 927
			rc = i;
			break;
		}
	}

	return rc;
}