main.c 23.2 KB
Newer Older
1
/*
2
 * Copyright (c) 2012-2014 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

V
Vladimir Kondratiev 已提交
32 33 34 35
static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");

V
Vladimir Kondratiev 已提交
36 37 38 39 40
static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;

module_param(itr_trsh, uint, S_IRUGO);
MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");

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

56
	if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
57 58 59 60 61 62 63 64 65 66 67 68 69
		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.");

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

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 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 145
	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
		     sta->status);
146

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

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

164
	for (i = 0; i < WIL_STA_TID_NUM; i++) {
165 166 167 168 169 170
		struct wil_tid_ampdu_rx *r;
		unsigned long flags;

		spin_lock_irqsave(&sta->tid_rx_lock, flags);

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

		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
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 219 220 221

	/* link state */
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		wil_link_off(wil);
		if (test_bit(wil_status_fwconnected, &wil->status)) {
			clear_bit(wil_status_fwconnected, &wil->status);
222
			cfg80211_disconnected(ndev, reason_code,
223 224 225 226 227 228 229 230 231 232
					      NULL, 0, GFP_KERNEL);
		} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
			cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
						WLAN_STATUS_UNSPECIFIED_FAILURE,
						GFP_KERNEL);
		}
		clear_bit(wil_status_fwconnecting, &wil->status);
		break;
	default:
		break;
233 234 235 236 237 238 239 240
	}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

350 351 352
static int wil_find_free_vring(struct wil6210_priv *wil)
{
	int i;
353

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

361 362 363 364 365 366
static void wil_connect_worker(struct work_struct *work)
{
	int rc;
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						connect_worker);
	int cid = wil->pending_connect_cid;
367
	int ringid = wil_find_free_vring(wil);
368 369 370 371 372 373 374 375

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

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

376
	rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
377
	wil->pending_connect_cid = -1;
378 379
	if (rc == 0) {
		wil->sta[cid].status = wil_sta_connected;
380
		wil_link_on(wil);
381 382 383
	} else {
		wil->sta[cid].status = wil_sta_unused;
	}
384 385
}

386 387
int wil_priv_init(struct wil6210_priv *wil)
{
388 389
	uint i;

390
	wil_dbg_misc(wil, "%s()\n", __func__);
391

392
	memset(wil->sta, 0, sizeof(wil->sta));
393 394
	for (i = 0; i < WIL6210_MAX_CID; i++)
		spin_lock_init(&wil->sta[i].tid_rx_lock);
395

396 397
	mutex_init(&wil->mutex);
	mutex_init(&wil->wmi_mutex);
V
Vladimir Kondratiev 已提交
398
	mutex_init(&wil->back_rx_mutex);
399
	mutex_init(&wil->back_tx_mutex);
400 401

	init_completion(&wil->wmi_ready);
402
	init_completion(&wil->wmi_call);
403 404 405

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

408
	INIT_WORK(&wil->connect_worker, wil_connect_worker);
409 410
	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
V
Vladimir Kondratiev 已提交
411
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
V
Vladimir Kondratiev 已提交
412
	INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
413
	INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
414 415

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
V
Vladimir Kondratiev 已提交
416
	INIT_LIST_HEAD(&wil->back_rx_pending);
417
	INIT_LIST_HEAD(&wil->back_tx_pending);
418
	spin_lock_init(&wil->wmi_ev_lock);
419
	init_waitqueue_head(&wil->wq);
420

V
Vladimir Kondratiev 已提交
421
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
422 423 424
	if (!wil->wmi_wq)
		return -EAGAIN;

V
Vladimir Kondratiev 已提交
425 426 427
	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
	if (!wil->wq_service)
		goto out_wmi_wq;
428

429
	wil->last_fw_recovery = jiffies;
V
Vladimir Kondratiev 已提交
430
	wil->itr_trsh = itr_trsh;
431

432
	return 0;
V
Vladimir Kondratiev 已提交
433 434 435 436 437

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
438 439
}

440 441 442 443
/**
 * wil6210_disconnect - disconnect one connection
 * @wil: driver context
 * @bssid: peer to disconnect, NULL to disconnect all
444
 * @reason_code: Reason code for the Disassociation frame
445 446 447 448 449 450
 * @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,
451
			u16 reason_code, bool from_event)
452
{
453 454
	wil_dbg_misc(wil, "%s()\n", __func__);

455
	del_timer_sync(&wil->connect_timer);
456
	_wil6210_disconnect(wil, bssid, reason_code, from_event);
457 458 459 460
}

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

463
	wil_set_recovery_state(wil, fw_recovery_idle);
464
	del_timer_sync(&wil->scan_timer);
465
	cancel_work_sync(&wil->disconnect_worker);
V
Vladimir Kondratiev 已提交
466
	cancel_work_sync(&wil->fw_error_worker);
467
	mutex_lock(&wil->mutex);
468
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
469
	mutex_unlock(&wil->mutex);
470
	wmi_event_flush(wil);
V
Vladimir Kondratiev 已提交
471 472
	wil_back_rx_flush(wil);
	cancel_work_sync(&wil->back_rx_worker);
473 474
	wil_back_tx_flush(wil);
	cancel_work_sync(&wil->back_tx_worker);
V
Vladimir Kondratiev 已提交
475
	destroy_workqueue(wil->wq_service);
476 477 478
	destroy_workqueue(wil->wmi_wq);
}

V
Vladimir Kondratiev 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
/* 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);
}

501
static int wil_target_reset(struct wil6210_priv *wil)
502
{
V
Vladimir Kondratiev 已提交
503
	int delay = 0;
V
Vladimir Kondratiev 已提交
504
	u32 x;
505
	u32 rev_id;
506
	bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
507

508
	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
509

510
	wil->hw_version = R(RGF_USER_FW_REV_ID);
511
	rev_id = wil->hw_version & 0xff;
512 513 514

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
515 516 517 518
	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);
519

V
Vladimir Kondratiev 已提交
520 521 522
	/* Clear Fw Download notification */
	C(RGF_USER_USAGE_6, BIT(0));

523
	if (is_sparrow) {
V
Vladimir Kondratiev 已提交
524 525 526 527 528 529 530 531 532 533 534 535 536 537
		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;
		}
		/* 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);

538
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
V
Vladimir Kondratiev 已提交
539
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
540 541
	}

542 543
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
V
Vladimir Kondratiev 已提交
544 545
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
546

547 548
	if (is_sparrow) {
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
V
Vladimir Kondratiev 已提交
549
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
550 551
	}

552 553 554 555 556
	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);

557 558 559
	if (is_sparrow) {
		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
		/* reset A2 PCIE AHB */
560
		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
561 562 563 564 565 566 567 568 569
	} else {
		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
		if (rev_id == 1) {
			/* reset A1 BOTH PCIE AHB & PCIE RGF */
			W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
		} else {
			W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
			W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
		}
570
	}
571 572

	/* TODO: check order here!!! Erez code is different */
573 574
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);

575
	/* wait until device ready. typical time is 200..250 msec */
576
	do {
577
		msleep(RST_DELAY);
V
Vladimir Kondratiev 已提交
578
		x = R(RGF_USER_HW_MACHINE_STATE);
579
		if (delay++ > RST_COUNT) {
580
			wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
V
Vladimir Kondratiev 已提交
581
				x);
582
			return -ETIME;
583
		}
V
Vladimir Kondratiev 已提交
584
	} while (x != HW_MACHINE_BOOT_DONE);
585

586 587
	/* TODO: Erez check rev_id != 1 */
	if (!is_sparrow && (rev_id != 1))
588
		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
589

590 591
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

592
	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
593
	return 0;
V
Vladimir Kondratiev 已提交
594
}
595

V
Vladimir Kondratiev 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
/**
 * wil_set_itr_trsh: - apply interrupt coalescing params
 */
void wil_set_itr_trsh(struct wil6210_priv *wil)
{
	/* disable, use usec resolution */
	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK);

	/* disable interrupt moderation for monitor
	 * to get better timestamp precision
	 */
	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
		return;

	wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh);
	W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh);
	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN |
	  BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */
}

616
#undef R
617 618
#undef W
#undef S
619
#undef C
620 621 622 623 624 625 626 627 628 629 630 631 632 633

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

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

635 636 637 638
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
639 640
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
641 642 643 644 645 646 647 648 649 650 651 652 653
	}
	return 0;
}

/*
 * We reset all the structures, and we reset the UMAC.
 * After calling this routine, you're expected to reload
 * the firmware.
 */
int wil_reset(struct wil6210_priv *wil)
{
	int rc;

654 655
	wil_dbg_misc(wil, "%s()\n", __func__);

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

	cancel_work_sync(&wil->disconnect_worker);
660
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
661

662 663
	wil->status = 0; /* prevent NAPI from being scheduled */

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

672
	wil_mask_irq(wil);
673

674 675
	wmi_event_flush(wil);

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

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

V
Vladimir Kondratiev 已提交
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
	if (!no_fw_load) {
		wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
		wil_halt_cpu(wil);
		/* Loading f/w from the file */
		rc = wil_request_firmware(wil, WIL_FW_NAME);
		if (rc)
			return rc;

		/* clear any interrupts which on-card-firmware may have set */
		wil6210_clear_irq(wil);
		{ /* CAF_ICR - clear and mask */
			u32 a = HOSTADDR(RGF_CAF_ICR) +
				offsetof(struct RGF_ICR, ICR);
			u32 m = HOSTADDR(RGF_CAF_ICR) +
				offsetof(struct RGF_ICR, IMV);
			u32 icr = ioread32(wil->csr + a);

			iowrite32(icr, wil->csr + a); /* W1C */
			iowrite32(~0, wil->csr + m);
			wmb(); /* wait for completion */
		}
		wil_release_cpu(wil);
	} else {
		wil_info(wil, "Use firmware from on-card flash\n");
	}
709

710 711
	/* init after reset */
	wil->pending_connect_cid = -1;
712
	reinit_completion(&wil->wmi_ready);
713
	reinit_completion(&wil->wmi_call);
714

715
	wil_unmask_irq(wil);
716 717 718 719 720 721 722

	/* we just started MAC, wait for FW ready */
	rc = wil_wait_for_fw_ready(wil);

	return rc;
}

V
Vladimir Kondratiev 已提交
723 724 725
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
726
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
727 728
	schedule_work(&wil->fw_error_worker);
}
729 730 731 732 733

void wil_link_on(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil_to_ndev(wil);

734
	wil_dbg_misc(wil, "%s()\n", __func__);
735 736

	netif_carrier_on(ndev);
737
	wil_dbg_misc(wil, "netif_tx_wake : link on\n");
738 739 740 741 742 743 744
	netif_tx_wake_all_queues(ndev);
}

void wil_link_off(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil_to_ndev(wil);

745
	wil_dbg_misc(wil, "%s()\n", __func__);
746 747

	netif_tx_stop_all_queues(ndev);
748
	wil_dbg_misc(wil, "netif_tx_stop : link off\n");
749 750 751
	netif_carrier_off(ndev);
}

752
int __wil_up(struct wil6210_priv *wil)
753 754 755 756 757
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

758 759
	WARN_ON(!mutex_is_locked(&wil->mutex));

760 761 762 763
	rc = wil_reset(wil);
	if (rc)
		return rc;

764
	/* Rx VRING. After MAC and beacon */
765
	rc = wil_rx_init(wil, 1 << rx_ring_order);
766 767 768
	if (rc)
		return rc;

769 770
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
771
		wil_dbg_misc(wil, "type: STATION\n");
772 773 774
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
775
		wil_dbg_misc(wil, "type: AP\n");
776 777 778
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
779
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
780 781 782
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
783
		wil_dbg_misc(wil, "type: P2P_GO\n");
784 785 786
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
787
		wil_dbg_misc(wil, "type: Monitor\n");
788 789 790 791 792 793 794 795 796 797
		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);

798
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
799 800
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
801
	set_bit(wil_status_napi_en, &wil->status);
V
Vladimir Kondratiev 已提交
802

803 804 805 806
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

807 808 809 810 811 812 813
	return 0;
}

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

814 815
	wil_dbg_misc(wil, "%s()\n", __func__);

816 817 818 819 820 821 822
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

823
int __wil_down(struct wil6210_priv *wil)
824
{
825 826 827
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

828 829
	WARN_ON(!mutex_is_locked(&wil->mutex));

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

833 834 835 836 837 838 839
	wil_disable_irq(wil);
	if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
		wil_dbg_misc(wil, "NAPI disable\n");
	}
	wil_enable_irq(wil);
V
Vladimir Kondratiev 已提交
840

841
	if (wil->scan_request) {
842 843
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
844
		del_timer_sync(&wil->scan_timer);
845 846 847 848
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	if (test_bit(wil_status_fwconnected, &wil->status) ||
	    test_bit(wil_status_fwconnecting, &wil->status))
		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

	/* make sure wil is idle (not connected) */
	mutex_unlock(&wil->mutex);
	while (iter--) {
		int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
			   !test_bit(wil_status_fwconnecting, &wil->status);
		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");

867 868 869 870 871 872 873 874 875
	wil_rx_fini(wil);

	return 0;
}

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

876 877
	wil_dbg_misc(wil, "%s()\n", __func__);

878
	wil_set_recovery_state(wil, fw_recovery_idle);
879 880 881 882 883 884
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
885 886 887 888 889 890 891 892

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) &&
893
		    ether_addr_equal(wil->sta[i].addr, mac)) {
894 895 896 897 898 899 900
			rc = i;
			break;
		}
	}

	return rc;
}