main.c 23.3 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 61 62 63 64 65 66 67 68
		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.");

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT;
static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT;

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

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

102 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
/*
 * 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++);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

352 353 354
static int wil_find_free_vring(struct wil6210_priv *wil)
{
	int i;
355

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

363 364 365 366 367
static void wil_connect_worker(struct work_struct *work)
{
	int rc;
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						connect_worker);
368 369
	struct net_device *ndev = wil_to_ndev(wil);

370
	int cid = wil->pending_connect_cid;
371
	int ringid = wil_find_free_vring(wil);
372 373 374 375 376 377 378 379

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

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

380
	rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
381
	wil->pending_connect_cid = -1;
382 383
	if (rc == 0) {
		wil->sta[cid].status = wil_sta_connected;
384
		netif_tx_wake_all_queues(ndev);
385 386 387
	} else {
		wil->sta[cid].status = wil_sta_unused;
	}
388 389
}

390 391
int wil_priv_init(struct wil6210_priv *wil)
{
392 393
	uint i;

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

396
	memset(wil->sta, 0, sizeof(wil->sta));
397 398
	for (i = 0; i < WIL6210_MAX_CID; i++)
		spin_lock_init(&wil->sta[i].tid_rx_lock);
399

400 401
	mutex_init(&wil->mutex);
	mutex_init(&wil->wmi_mutex);
V
Vladimir Kondratiev 已提交
402
	mutex_init(&wil->back_rx_mutex);
403
	mutex_init(&wil->back_tx_mutex);
404
	mutex_init(&wil->probe_client_mutex);
405 406

	init_completion(&wil->wmi_ready);
407
	init_completion(&wil->wmi_call);
408 409 410

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

413
	INIT_WORK(&wil->connect_worker, wil_connect_worker);
414 415
	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
V
Vladimir Kondratiev 已提交
416
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
V
Vladimir Kondratiev 已提交
417
	INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
418
	INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
419
	INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
420 421

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
V
Vladimir Kondratiev 已提交
422
	INIT_LIST_HEAD(&wil->back_rx_pending);
423
	INIT_LIST_HEAD(&wil->back_tx_pending);
424
	INIT_LIST_HEAD(&wil->probe_client_pending);
425
	spin_lock_init(&wil->wmi_ev_lock);
426
	init_waitqueue_head(&wil->wq);
427

V
Vladimir Kondratiev 已提交
428
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
429 430 431
	if (!wil->wmi_wq)
		return -EAGAIN;

V
Vladimir Kondratiev 已提交
432 433 434
	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
	if (!wil->wq_service)
		goto out_wmi_wq;
435

436
	wil->last_fw_recovery = jiffies;
437 438 439 440
	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;
441

442 443
	if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
		rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
444
	return 0;
V
Vladimir Kondratiev 已提交
445 446 447 448 449

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
450 451
}

452 453 454 455
/**
 * wil6210_disconnect - disconnect one connection
 * @wil: driver context
 * @bssid: peer to disconnect, NULL to disconnect all
456
 * @reason_code: Reason code for the Disassociation frame
457 458 459 460 461 462
 * @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,
463
			u16 reason_code, bool from_event)
464
{
465 466
	wil_dbg_misc(wil, "%s()\n", __func__);

467
	del_timer_sync(&wil->connect_timer);
468
	_wil6210_disconnect(wil, bssid, reason_code, from_event);
469 470 471 472
}

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

475
	wil_set_recovery_state(wil, fw_recovery_idle);
476
	del_timer_sync(&wil->scan_timer);
477
	cancel_work_sync(&wil->disconnect_worker);
V
Vladimir Kondratiev 已提交
478
	cancel_work_sync(&wil->fw_error_worker);
479
	mutex_lock(&wil->mutex);
480
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
481
	mutex_unlock(&wil->mutex);
482
	wmi_event_flush(wil);
V
Vladimir Kondratiev 已提交
483 484
	wil_back_rx_flush(wil);
	cancel_work_sync(&wil->back_rx_worker);
485 486
	wil_back_tx_flush(wil);
	cancel_work_sync(&wil->back_tx_worker);
487 488
	wil_probe_client_flush(wil);
	cancel_work_sync(&wil->probe_client_worker);
V
Vladimir Kondratiev 已提交
489
	destroy_workqueue(wil->wq_service);
490 491 492
	destroy_workqueue(wil->wmi_wq);
}

V
Vladimir Kondratiev 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
/* 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);
}

515
static int wil_target_reset(struct wil6210_priv *wil)
516
{
V
Vladimir Kondratiev 已提交
517
	int delay = 0;
V
Vladimir Kondratiev 已提交
518
	u32 x;
519

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

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
524 525 526 527
	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);
528

V
Vladimir Kondratiev 已提交
529 530
	/* clear all boot loader "ready" bits */
	W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0);
V
Vladimir Kondratiev 已提交
531 532 533
	/* Clear Fw Download notification */
	C(RGF_USER_USAGE_6, BIT(0));

534 535 536 537 538 539 540 541
	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;
542
	}
543 544 545 546 547 548 549
	/* 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);
550

551 552
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
553
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0);
V
Vladimir Kondratiev 已提交
554
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
555

556 557
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
	W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
558

559 560 561 562 563
	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);

564 565
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */
566

567 568
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

V
Vladimir Kondratiev 已提交
569
	/* wait until device ready. typical time is 20..80 msec */
570
	do {
571
		msleep(RST_DELAY);
V
Vladimir Kondratiev 已提交
572
		x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready));
573
		if (delay++ > RST_COUNT) {
V
Vladimir Kondratiev 已提交
574
			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
V
Vladimir Kondratiev 已提交
575
				x);
576
			return -ETIME;
577
		}
V
Vladimir Kondratiev 已提交
578
	} while (!(x & BIT_BL_READY));
579

580 581
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

582 583 584 585
	/* 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);

586
	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
587
	return 0;
V
Vladimir Kondratiev 已提交
588
}
589 590 591 592 593 594 595 596 597 598

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 已提交
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
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;
}

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

630 631 632 633
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
634 635
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
636 637 638 639 640 641 642 643 644
	}
	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 已提交
645
int wil_reset(struct wil6210_priv *wil, bool load_fw)
646 647 648
{
	int rc;

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

651 652 653
	if (wil->hw_version == HW_VER_UNKNOWN)
		return -ENODEV;

654
	WARN_ON(!mutex_is_locked(&wil->mutex));
655
	WARN_ON(test_bit(wil_status_napi_en, wil->status));
656 657

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

660 661
	/* prevent NAPI from being scheduled */
	bitmap_zero(wil->status, wil_status_last);
662

V
Vladimir Kondratiev 已提交
663 664 665
	if (wil->scan_request) {
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
666
		del_timer_sync(&wil->scan_timer);
V
Vladimir Kondratiev 已提交
667 668 669 670
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

671
	wil_mask_irq(wil);
672

673 674
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
675
	flush_workqueue(wil->wq_service);
676
	flush_workqueue(wil->wmi_wq);
677

678
	rc = wil_target_reset(wil);
679
	wil_rx_fini(wil);
680 681 682
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
683 684 685 686 687 688 689 690
	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 已提交
691 692 693 694 695
		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 已提交
696 697 698 699 700 701
		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 已提交
702

V
Vladimir Kondratiev 已提交
703 704 705
		/* clear any interrupts which on-card-firmware
		 * may have set
		 */
V
Vladimir Kondratiev 已提交
706
		wil6210_clear_irq(wil);
V
Vladimir Kondratiev 已提交
707 708 709 710 711
		/* 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 已提交
712 713
		wil_release_cpu(wil);
	}
714

715 716
	/* init after reset */
	wil->pending_connect_cid = -1;
717
	wil->ap_isolate = 0;
718
	reinit_completion(&wil->wmi_ready);
719
	reinit_completion(&wil->wmi_call);
720

V
Vladimir Kondratiev 已提交
721 722 723
	if (load_fw) {
		wil_configure_interrupt_moderation(wil);
		wil_unmask_irq(wil);
724

V
Vladimir Kondratiev 已提交
725 726 727
		/* we just started MAC, wait for FW ready */
		rc = wil_wait_for_fw_ready(wil);
	}
728 729 730 731

	return rc;
}

V
Vladimir Kondratiev 已提交
732 733 734 735 736
#undef R
#undef W
#undef S
#undef C

V
Vladimir Kondratiev 已提交
737 738 739
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
740
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
741 742
	schedule_work(&wil->fw_error_worker);
}
743

744
int __wil_up(struct wil6210_priv *wil)
745 746 747 748 749
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

750 751
	WARN_ON(!mutex_is_locked(&wil->mutex));

V
Vladimir Kondratiev 已提交
752
	rc = wil_reset(wil, true);
753 754 755
	if (rc)
		return rc;

756
	/* Rx VRING. After MAC and beacon */
757
	rc = wil_rx_init(wil, 1 << rx_ring_order);
758 759 760
	if (rc)
		return rc;

761 762
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
763
		wil_dbg_misc(wil, "type: STATION\n");
764 765 766
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
767
		wil_dbg_misc(wil, "type: AP\n");
768 769 770
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
771
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
772 773 774
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
775
		wil_dbg_misc(wil, "type: P2P_GO\n");
776 777 778
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
779
		wil_dbg_misc(wil, "type: Monitor\n");
780 781 782 783 784 785 786 787 788 789
		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);

790
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
791 792
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
793
	set_bit(wil_status_napi_en, wil->status);
V
Vladimir Kondratiev 已提交
794

795 796 797 798
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

799 800 801 802 803 804 805
	return 0;
}

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

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

808 809 810 811 812 813 814
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

815
int __wil_down(struct wil6210_priv *wil)
816
{
817 818 819
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

820 821
	WARN_ON(!mutex_is_locked(&wil->mutex));

822 823 824
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

825
	wil_disable_irq(wil);
826
	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
827 828 829 830 831
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
		wil_dbg_misc(wil, "NAPI disable\n");
	}
	wil_enable_irq(wil);
V
Vladimir Kondratiev 已提交
832

833
	if (wil->scan_request) {
834 835
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
836
		del_timer_sync(&wil->scan_timer);
837 838 839 840
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

841 842
	if (test_bit(wil_status_fwconnected, wil->status) ||
	    test_bit(wil_status_fwconnecting, wil->status))
843 844 845 846 847
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
848 849
		int idle = !test_bit(wil_status_fwconnected, wil->status) &&
			   !test_bit(wil_status_fwconnecting, wil->status);
850 851 852 853 854 855 856 857 858
		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 已提交
859
	wil_reset(wil, false);
860 861 862 863 864 865 866 867

	return 0;
}

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

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

870
	wil_set_recovery_state(wil, fw_recovery_idle);
871 872 873 874 875 876
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
877 878 879 880 881 882 883 884

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) &&
885
		    ether_addr_equal(wil->sta[i].addr, mac)) {
886 887 888 889 890 891 892
			rc = i;
			break;
		}
	}

	return rc;
}