main.c 22.6 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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
/* 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.
 */
unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
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;

	if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
		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 191 192 193 194 195
	struct wireless_dev *wdev = wil->wdev;

	might_sleep();
	if (bssid) {
		cid = wil_find_cid(wil, bssid);
		wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
	} else {
		wil_dbg_misc(wil, "%s(all)\n", __func__);
V
Vladimir Kondratiev 已提交
196 197
	}

198
	if (cid >= 0) /* disconnect 1 peer */
199
		wil_disconnect_cid(wil, cid, reason_code, from_event);
200 201
	else /* disconnect all */
		for (cid = 0; cid < WIL6210_MAX_CID; cid++)
202
			wil_disconnect_cid(wil, cid, reason_code, from_event);
203 204 205 206 207 208 209 210

	/* 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);
211
			cfg80211_disconnected(ndev, reason_code,
212 213 214 215 216 217 218 219 220 221
					      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;
222 223 224 225 226 227 228 229
	}
}

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

230
	mutex_lock(&wil->mutex);
231
	_wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false);
232
	mutex_unlock(&wil->mutex);
233 234 235 236 237 238
}

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

239
	wil_dbg_misc(wil, "Connect timeout\n");
240 241 242 243 244 245 246

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

247 248 249 250 251 252
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");
253
	wil->recovery_state = fw_recovery_pending;
254 255 256
	schedule_work(&wil->fw_error_worker);
}

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
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 已提交
281 282
static void wil_fw_error_worker(struct work_struct *work)
{
283 284
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
V
Vladimir Kondratiev 已提交
285 286 287 288
	struct wireless_dev *wdev = wil->wdev;

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

289 290 291 292 293
	if (!netif_running(wil_to_ndev(wil))) {
		wil_info(wil, "No recovery - interface is down\n");
		return;
	}

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	/* 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;

311
	mutex_lock(&wil->mutex);
V
Vladimir Kondratiev 已提交
312 313 314 315
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_MONITOR:
316
		wil_info(wil, "fw error recovery requested (try %d)...\n",
317
			 wil->recovery_count);
318 319 320 321 322
		if (!no_fw_recovery)
			wil->recovery_state = fw_recovery_running;
		if (0 != wil_wait_for_recovery(wil))
			break;

323 324
		__wil_down(wil);
		__wil_up(wil);
V
Vladimir Kondratiev 已提交
325 326 327
		break;
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
328
		wil_info(wil, "No recovery for AP-like interface\n");
V
Vladimir Kondratiev 已提交
329 330 331
		/* recovery in these modes is done by upper layers */
		break;
	default:
332 333
		wil_err(wil, "No recovery - unknown interface type %d\n",
			wdev->iftype);
V
Vladimir Kondratiev 已提交
334 335
		break;
	}
336
	mutex_unlock(&wil->mutex);
V
Vladimir Kondratiev 已提交
337 338
}

339 340 341
static int wil_find_free_vring(struct wil6210_priv *wil)
{
	int i;
342

343 344 345 346 347 348 349
	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
		if (!wil->vring_tx[i].va)
			return i;
	}
	return -EINVAL;
}

350 351 352 353 354 355
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;
356
	int ringid = wil_find_free_vring(wil);
357 358 359 360 361 362 363 364

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

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

365
	rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
366
	wil->pending_connect_cid = -1;
367 368
	if (rc == 0) {
		wil->sta[cid].status = wil_sta_connected;
369
		wil_link_on(wil);
370 371 372
	} else {
		wil->sta[cid].status = wil_sta_unused;
	}
373 374
}

375 376
int wil_priv_init(struct wil6210_priv *wil)
{
377 378
	uint i;

379
	wil_dbg_misc(wil, "%s()\n", __func__);
380

381
	memset(wil->sta, 0, sizeof(wil->sta));
382 383
	for (i = 0; i < WIL6210_MAX_CID; i++)
		spin_lock_init(&wil->sta[i].tid_rx_lock);
384

385 386
	mutex_init(&wil->mutex);
	mutex_init(&wil->wmi_mutex);
V
Vladimir Kondratiev 已提交
387
	mutex_init(&wil->back_rx_mutex);
388 389

	init_completion(&wil->wmi_ready);
390
	init_completion(&wil->wmi_call);
391 392 393

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

396
	INIT_WORK(&wil->connect_worker, wil_connect_worker);
397 398
	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
V
Vladimir Kondratiev 已提交
399
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
V
Vladimir Kondratiev 已提交
400
	INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
401 402

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
V
Vladimir Kondratiev 已提交
403
	INIT_LIST_HEAD(&wil->back_rx_pending);
404
	spin_lock_init(&wil->wmi_ev_lock);
405
	init_waitqueue_head(&wil->wq);
406

V
Vladimir Kondratiev 已提交
407
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
408 409 410
	if (!wil->wmi_wq)
		return -EAGAIN;

V
Vladimir Kondratiev 已提交
411 412 413
	wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
	if (!wil->wq_service)
		goto out_wmi_wq;
414

415
	wil->last_fw_recovery = jiffies;
V
Vladimir Kondratiev 已提交
416
	wil->itr_trsh = itr_trsh;
417

418
	return 0;
V
Vladimir Kondratiev 已提交
419 420 421 422 423

out_wmi_wq:
	destroy_workqueue(wil->wmi_wq);

	return -EAGAIN;
424 425
}

426 427 428 429
/**
 * wil6210_disconnect - disconnect one connection
 * @wil: driver context
 * @bssid: peer to disconnect, NULL to disconnect all
430
 * @reason_code: Reason code for the Disassociation frame
431 432 433 434 435 436
 * @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,
437
			u16 reason_code, bool from_event)
438
{
439 440
	wil_dbg_misc(wil, "%s()\n", __func__);

441
	del_timer_sync(&wil->connect_timer);
442
	_wil6210_disconnect(wil, bssid, reason_code, from_event);
443 444 445 446
}

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

449
	wil_set_recovery_state(wil, fw_recovery_idle);
450
	del_timer_sync(&wil->scan_timer);
451
	cancel_work_sync(&wil->disconnect_worker);
V
Vladimir Kondratiev 已提交
452
	cancel_work_sync(&wil->fw_error_worker);
453
	mutex_lock(&wil->mutex);
454
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
455
	mutex_unlock(&wil->mutex);
456
	wmi_event_flush(wil);
V
Vladimir Kondratiev 已提交
457 458 459
	wil_back_rx_flush(wil);
	cancel_work_sync(&wil->back_rx_worker);
	destroy_workqueue(wil->wq_service);
460 461 462
	destroy_workqueue(wil->wmi_wq);
}

V
Vladimir Kondratiev 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
/* 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);
}

485
static int wil_target_reset(struct wil6210_priv *wil)
486
{
V
Vladimir Kondratiev 已提交
487
	int delay = 0;
V
Vladimir Kondratiev 已提交
488
	u32 x;
489
	u32 rev_id;
490
	bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
491

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

494
	wil->hw_version = R(RGF_USER_FW_REV_ID);
495
	rev_id = wil->hw_version & 0xff;
496 497 498

	/* Clear MAC link up */
	S(RGF_HP_CTRL, BIT(15));
V
Vladimir Kondratiev 已提交
499 500 501 502
	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);
503

V
Vladimir Kondratiev 已提交
504 505 506
	/* Clear Fw Download notification */
	C(RGF_USER_USAGE_6, BIT(0));

507
	if (is_sparrow) {
V
Vladimir Kondratiev 已提交
508 509 510 511 512 513 514 515 516 517 518 519 520 521
		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);

522
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
V
Vladimir Kondratiev 已提交
523
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
524 525
	}

526 527
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
V
Vladimir Kondratiev 已提交
528 529
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
530

531 532
	if (is_sparrow) {
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
V
Vladimir Kondratiev 已提交
533
		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
534 535
	}

536 537 538 539 540
	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);

541 542 543
	if (is_sparrow) {
		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
		/* reset A2 PCIE AHB */
544
		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
545 546 547 548 549 550 551 552 553
	} 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);
		}
554
	}
555 556

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

559
	/* wait until device ready. typical time is 200..250 msec */
560
	do {
561
		msleep(RST_DELAY);
V
Vladimir Kondratiev 已提交
562
		x = R(RGF_USER_HW_MACHINE_STATE);
563
		if (delay++ > RST_COUNT) {
564
			wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
V
Vladimir Kondratiev 已提交
565
				x);
566
			return -ETIME;
567
		}
V
Vladimir Kondratiev 已提交
568
	} while (x != HW_MACHINE_BOOT_DONE);
569

570 571
	/* TODO: Erez check rev_id != 1 */
	if (!is_sparrow && (rev_id != 1))
572
		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
573

574 575
	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

576
	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
577
	return 0;
V
Vladimir Kondratiev 已提交
578
}
579

V
Vladimir Kondratiev 已提交
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
/**
 * 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 */
}

600
#undef R
601 602
#undef W
#undef S
603
#undef C
604 605 606 607 608 609 610 611 612 613 614 615 616 617

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

619 620 621 622
	if (0 == left) {
		wil_err(wil, "Firmware not ready\n");
		return -ETIME;
	} else {
623 624
		wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
			 jiffies_to_msecs(to-left), wil->hw_version);
625 626 627 628 629 630 631 632 633 634 635 636 637
	}
	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;

638 639
	wil_dbg_misc(wil, "%s()\n", __func__);

640
	WARN_ON(!mutex_is_locked(&wil->mutex));
641
	WARN_ON(test_bit(wil_status_napi_en, &wil->status));
642 643

	cancel_work_sync(&wil->disconnect_worker);
644
	wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
645

646 647
	wil->status = 0; /* prevent NAPI from being scheduled */

V
Vladimir Kondratiev 已提交
648 649 650
	if (wil->scan_request) {
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
651
		del_timer_sync(&wil->scan_timer);
V
Vladimir Kondratiev 已提交
652 653 654 655
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

656
	wil_mask_irq(wil);
657

658 659
	wmi_event_flush(wil);

V
Vladimir Kondratiev 已提交
660
	flush_workqueue(wil->wq_service);
661
	flush_workqueue(wil->wmi_wq);
662

663
	rc = wil_target_reset(wil);
664
	wil_rx_fini(wil);
665 666 667
	if (rc)
		return rc;

V
Vladimir Kondratiev 已提交
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
	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");
	}
693

694 695
	/* init after reset */
	wil->pending_connect_cid = -1;
696
	reinit_completion(&wil->wmi_ready);
697
	reinit_completion(&wil->wmi_call);
698

699
	wil_unmask_irq(wil);
700 701 702 703 704 705 706

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

	return rc;
}

V
Vladimir Kondratiev 已提交
707 708 709
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
710
	wil->recovery_state = fw_recovery_pending;
V
Vladimir Kondratiev 已提交
711 712
	schedule_work(&wil->fw_error_worker);
}
713 714 715 716 717

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

718
	wil_dbg_misc(wil, "%s()\n", __func__);
719 720

	netif_carrier_on(ndev);
721
	wil_dbg_misc(wil, "netif_tx_wake : link on\n");
722 723 724 725 726 727 728
	netif_tx_wake_all_queues(ndev);
}

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

729
	wil_dbg_misc(wil, "%s()\n", __func__);
730 731

	netif_tx_stop_all_queues(ndev);
732
	wil_dbg_misc(wil, "netif_tx_stop : link off\n");
733 734 735
	netif_carrier_off(ndev);
}

736
int __wil_up(struct wil6210_priv *wil)
737 738 739 740 741
{
	struct net_device *ndev = wil_to_ndev(wil);
	struct wireless_dev *wdev = wil->wdev;
	int rc;

742 743
	WARN_ON(!mutex_is_locked(&wil->mutex));

744 745 746 747
	rc = wil_reset(wil);
	if (rc)
		return rc;

748
	/* Rx VRING. After MAC and beacon */
749
	rc = wil_rx_init(wil, 1 << rx_ring_order);
750 751 752
	if (rc)
		return rc;

753 754
	switch (wdev->iftype) {
	case NL80211_IFTYPE_STATION:
755
		wil_dbg_misc(wil, "type: STATION\n");
756 757 758
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_AP:
759
		wil_dbg_misc(wil, "type: AP\n");
760 761 762
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_CLIENT:
763
		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
764 765 766
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_P2P_GO:
767
		wil_dbg_misc(wil, "type: P2P_GO\n");
768 769 770
		ndev->type = ARPHRD_ETHER;
		break;
	case NL80211_IFTYPE_MONITOR:
771
		wil_dbg_misc(wil, "type: Monitor\n");
772 773 774 775 776 777 778 779 780 781
		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);

782
	wil_dbg_misc(wil, "NAPI enable\n");
V
Vladimir Kondratiev 已提交
783 784
	napi_enable(&wil->napi_rx);
	napi_enable(&wil->napi_tx);
785
	set_bit(wil_status_napi_en, &wil->status);
V
Vladimir Kondratiev 已提交
786

787 788 789 790
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle,
					      WIL_MAX_BUS_REQUEST_KBPS);

791 792 793 794 795 796 797
	return 0;
}

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

798 799
	wil_dbg_misc(wil, "%s()\n", __func__);

800 801 802 803 804 805 806
	mutex_lock(&wil->mutex);
	rc = __wil_up(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}

807
int __wil_down(struct wil6210_priv *wil)
808
{
809 810 811
	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
			WAIT_FOR_DISCONNECT_INTERVAL_MS;

812 813
	WARN_ON(!mutex_is_locked(&wil->mutex));

814 815 816
	if (wil->platform_ops.bus_request)
		wil->platform_ops.bus_request(wil->platform_handle, 0);

817 818 819 820 821 822 823
	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 已提交
824

825
	if (wil->scan_request) {
826 827
		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
			     wil->scan_request);
828
		del_timer_sync(&wil->scan_timer);
829 830 831 832
		cfg80211_scan_done(wil->scan_request, true);
		wil->scan_request = NULL;
	}

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
	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");

851 852 853 854 855 856 857 858 859
	wil_rx_fini(wil);

	return 0;
}

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

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

862
	wil_set_recovery_state(wil, fw_recovery_idle);
863 864 865 866 867 868
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);

	return rc;
}
869 870 871 872 873 874 875 876

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) &&
877
		    ether_addr_equal(wil->sta[i].addr, mac)) {
878 879 880 881 882 883 884
			rc = i;
			break;
		}
	}

	return rc;
}