main.c 26.1 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
#include "wmi.h"
24
#include "boot_loader.h"
25 26 27

#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
28

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

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

37 38 39 40 41 42 43
/* 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 已提交
44

45 46 47
/* 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.
 */
48
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
49 50 51 52 53 54 55 56 57 58 59
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;

60
	if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
61 62 63 64 65
		ret = -EINVAL;

	return ret;
}

66
static const struct kernel_param_ops mtu_max_ops = {
67 68 69 70 71 72 73
	.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.");

74 75
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;
76
static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT;
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

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

95
static const struct kernel_param_ops ring_order_ops = {
96 97 98 99 100 101 102 103
	.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
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");
106

107 108 109
#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 */

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 140 141 142
/*
 * 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++);
}

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

152
	might_sleep();
153 154
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);
155 156

	if (sta->status != wil_sta_unused) {
157
		if (!from_event)
158
			wmi_disconnect_sta(wil, sta->addr, reason_code);
159

160 161 162 163 164 165 166 167 168
		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;
		}
169 170 171
		sta->status = wil_sta_unused;
	}

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

175
		spin_lock_bh(&sta->tid_rx_lock);
176 177

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

181
		spin_unlock_bh(&sta->tid_rx_lock);
182 183 184 185 186 187 188 189
	}
	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));
}

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

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

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

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

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

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

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

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

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

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

272
	clear_bit(wil_status_fwready, wil->status);
273
	wil_err(wil, "Scan timeout detected, start fw error recovery\n");
274
	wil_fw_error_recovery(wil);
275 276
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

427 428
int wil_priv_init(struct wil6210_priv *wil)
{
429 430
	uint i;

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

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

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

	init_completion(&wil->wmi_ready);
444
	init_completion(&wil->wmi_call);
445 446

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

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

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

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

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

474
	wil->last_fw_recovery = jiffies;
475 476 477 478
	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;
479

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

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
488 489
}

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

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

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

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

V
Vladimir Kondratiev 已提交
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
/* 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);
}

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

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

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
562 563 564 565
	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);
566

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

573 574 575 576 577 578 579 580
	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;
581
	}
582 583 584 585 586 587 588
	/* 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);
589

590 591
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
592
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
V
Vladimir Kondratiev 已提交
593
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
594

595 596
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
597

598 599 600 601 602
	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);

603 604
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */
605

606 607
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

V
Vladimir Kondratiev 已提交
608
	/* wait until device ready. typical time is 20..80 msec */
609
	do {
610
		msleep(RST_DELAY);
611 612
		x = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0,
					     boot_loader_ready));
613 614 615 616
		if (x1 != x) {
			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
			x1 = x;
		}
617
		if (delay++ > RST_COUNT) {
V
Vladimir Kondratiev 已提交
618
			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
V
Vladimir Kondratiev 已提交
619
				x);
620
			return -ETIME;
621
		}
622
	} while (x != BL_READY);
623

624 625
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

626 627 628 629
	/* 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);

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

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 已提交
643 644 645
static int wil_get_bl_info(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil_to_ndev(wil);
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
	union {
		struct bl_dedicated_registers_v0 bl0;
		struct bl_dedicated_registers_v1 bl1;
	} bl;
	u32 bl_ver;
	u8 *mac;
	u16 rf_status;

	bl_ver = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0,
					  boot_loader_struct_version));
	switch (bl_ver) {
	case 0:
		wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL),
				     sizeof(bl.bl0));
		le32_to_cpus(&bl.bl0.boot_loader_ready);
		le32_to_cpus(&bl.bl0.boot_loader_struct_version);
		le32_to_cpus(&bl.bl0.rf_type);
		le32_to_cpus(&bl.bl0.baseband_type);
		mac = bl.bl0.mac_address;
		rf_status = 0; /* actually, unknown */
		wil_info(wil,
			 "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n",
			 bl_ver, mac,
			 bl.bl0.rf_type, bl.bl0.baseband_type);
		wil_info(wil, "Boot Loader build unknown for struct v0\n");
		break;
	case 1:
		wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL),
				     sizeof(bl.bl1));
		le32_to_cpus(&bl.bl1.boot_loader_ready);
		le32_to_cpus(&bl.bl1.boot_loader_struct_version);
		le16_to_cpus(&bl.bl1.rf_type);
		rf_status = le16_to_cpu(bl.bl1.rf_status);
		le32_to_cpus(&bl.bl1.baseband_type);
		le16_to_cpus(&bl.bl1.bl_version_subminor);
		le16_to_cpus(&bl.bl1.bl_version_build);
		mac = bl.bl1.mac_address;
		wil_info(wil,
			 "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n",
			 bl_ver, mac,
			 bl.bl1.rf_type, rf_status,
			 bl.bl1.baseband_type);
		wil_info(wil, "Boot Loader build %d.%d.%d.%d\n",
			 bl.bl1.bl_version_major, bl.bl1.bl_version_minor,
			 bl.bl1.bl_version_subminor, bl.bl1.bl_version_build);
		break;
	default:
		wil_err(wil, "BL: unsupported struct version 0x%08x\n", bl_ver);
		return -EINVAL;
	}
V
Vladimir Kondratiev 已提交
696

697 698
	if (!is_valid_ether_addr(mac)) {
		wil_err(wil, "BL: Invalid MAC %pM\n", mac);
V
Vladimir Kondratiev 已提交
699 700 701
		return -EINVAL;
	}

702
	ether_addr_copy(ndev->perm_addr, mac);
V
Vladimir Kondratiev 已提交
703
	if (!is_valid_ether_addr(ndev->dev_addr))
704 705 706 707 708 709 710
		ether_addr_copy(ndev->dev_addr, mac);

	if (rf_status) {/* bad RF cable? */
		wil_err(wil, "RF communication error 0x%04x",
			rf_status);
		return -EAGAIN;
	}
V
Vladimir Kondratiev 已提交
711 712 713 714

	return 0;
}

715 716 717 718
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);
719

720 721 722 723
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
724 725
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
726 727 728 729 730 731 732 733 734
	}
	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 已提交
735
int wil_reset(struct wil6210_priv *wil, bool load_fw)
736 737 738
{
	int rc;

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

741 742 743
	if (wil->hw_version == HW_VER_UNKNOWN)
		return -ENODEV;

744
	WARN_ON(!mutex_is_locked(&wil->mutex));
745
	WARN_ON(test_bit(wil_status_napi_en, wil->status));
746

V
Vladimir Kondratiev 已提交
747 748 749 750 751 752 753 754 755 756 757
	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;
	}

758
	cancel_work_sync(&wil->disconnect_worker);
759
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
760
	wil_bcast_fini(wil);
761

762 763
	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
764

V
Vladimir Kondratiev 已提交
765 766 767
	if (wil->scan_request) {
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
768
		del_timer_sync(&wil->scan_timer);
V
Vladimir Kondratiev 已提交
769 770 771 772
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

773
	wil_mask_irq(wil);
774

775 776
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
777
	flush_workqueue(wil->wq_service);
778
	flush_workqueue(wil->wmi_wq);
779

780
	rc = wil_target_reset(wil);
781
	wil_rx_fini(wil);
782 783 784
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
785
	rc = wil_get_bl_info(wil);
786 787
	if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
		rc = 0;
V
Vladimir Kondratiev 已提交
788 789 790 791 792 793 794
	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 已提交
795 796 797 798 799
		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 已提交
800 801 802 803 804 805
		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 已提交
806

V
Vladimir Kondratiev 已提交
807 808 809
		/* clear any interrupts which on-card-firmware
		 * may have set
		 */
V
Vladimir Kondratiev 已提交
810
		wil6210_clear_irq(wil);
V
Vladimir Kondratiev 已提交
811 812 813 814 815
		/* 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 已提交
816 817
		wil_release_cpu(wil);
	}
818

819 820
	/* init after reset */
	wil->pending_connect_cid = -1;
821
	wil->ap_isolate = 0;
822
	reinit_completion(&wil->wmi_ready);
823
	reinit_completion(&wil->wmi_call);
824

V
Vladimir Kondratiev 已提交
825 826 827
	if (load_fw) {
		wil_configure_interrupt_moderation(wil);
		wil_unmask_irq(wil);
828

V
Vladimir Kondratiev 已提交
829 830
		/* we just started MAC, wait for FW ready */
		rc = wil_wait_for_fw_ready(wil);
831 832
		if (rc == 0) /* check FW is responsive */
			rc = wmi_echo(wil);
V
Vladimir Kondratiev 已提交
833
	}
834 835 836 837

	return rc;
}

V
Vladimir Kondratiev 已提交
838 839 840 841 842
#undef R
#undef W
#undef S
#undef C

V
Vladimir Kondratiev 已提交
843 844 845
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
846
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
847 848
	schedule_work(&wil->fw_error_worker);
}
849

850
int __wil_up(struct wil6210_priv *wil)
851 852 853 854 855
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

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

V
Vladimir Kondratiev 已提交
858
	rc = wil_reset(wil, true);
859 860 861
	if (rc)
		return rc;

862
	/* Rx VRING. After MAC and beacon */
863
	rc = wil_rx_init(wil, 1 << rx_ring_order);
864 865 866
	if (rc)
		return rc;

867 868
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
869
		wil_dbg_misc(wil, "type: STATION\n");
870 871 872
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
873
		wil_dbg_misc(wil, "type: AP\n");
874 875 876
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
877
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
878 879 880
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
881
		wil_dbg_misc(wil, "type: P2P_GO\n");
882 883 884
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
885
		wil_dbg_misc(wil, "type: Monitor\n");
886 887 888 889 890 891 892 893 894 895
		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);

896
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
897 898
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
899
	set_bit(wil_status_napi_en, wil->status);
V
Vladimir Kondratiev 已提交
900

901 902 903 904
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

905 906 907 908 909 910 911
	return 0;
}

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

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

914 915 916 917 918 919 920
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

921
int __wil_down(struct wil6210_priv *wil)
922
{
923 924 925
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

926 927
	WARN_ON(!mutex_is_locked(&wil->mutex));

928 929 930
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

931
	wil_disable_irq(wil);
932
	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
933 934 935 936 937
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
		wil_dbg_misc(wil, "NAPI disable\n");
	}
	wil_enable_irq(wil);
V
Vladimir Kondratiev 已提交
938

939
	if (wil->scan_request) {
940 941
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
942
		del_timer_sync(&wil->scan_timer);
943 944 945 946
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

947 948
	if (test_bit(wil_status_fwconnected, wil->status) ||
	    test_bit(wil_status_fwconnecting, wil->status))
949 950 951 952 953
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
954 955
		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
			   !test_bit(wil_status_fwconnecting, wil->status);
956 957 958 959 960 961 962 963 964
		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 已提交
965
	wil_reset(wil, false);
966 967 968 969 970 971 972 973

	return 0;
}

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

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

976
	wil_set_recovery_state(wil, fw_recovery_idle);
977 978 979 980 981 982
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
983 984 985 986 987 988 989 990

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) &&
991
		    ether_addr_equal(wil->sta[i].addr, mac)) {
992 993 994 995 996 997 998
			rc = i;
			break;
		}
	}

	return rc;
}