12be7d22fSVladimir Kondratiev /*
22be7d22fSVladimir Kondratiev  * Copyright (c) 2012 Qualcomm Atheros, Inc.
32be7d22fSVladimir Kondratiev  *
42be7d22fSVladimir Kondratiev  * Permission to use, copy, modify, and/or distribute this software for any
52be7d22fSVladimir Kondratiev  * purpose with or without fee is hereby granted, provided that the above
62be7d22fSVladimir Kondratiev  * copyright notice and this permission notice appear in all copies.
72be7d22fSVladimir Kondratiev  *
82be7d22fSVladimir Kondratiev  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
92be7d22fSVladimir Kondratiev  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
102be7d22fSVladimir Kondratiev  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
112be7d22fSVladimir Kondratiev  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
122be7d22fSVladimir Kondratiev  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
132be7d22fSVladimir Kondratiev  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
142be7d22fSVladimir Kondratiev  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
152be7d22fSVladimir Kondratiev  */
162be7d22fSVladimir Kondratiev 
172be7d22fSVladimir Kondratiev #include <linux/moduleparam.h>
182be7d22fSVladimir Kondratiev #include <linux/if_arp.h>
192be7d22fSVladimir Kondratiev 
202be7d22fSVladimir Kondratiev #include "wil6210.h"
21b4490f42SVladimir Kondratiev #include "txrx.h"
222be7d22fSVladimir Kondratiev 
232be7d22fSVladimir Kondratiev /*
242be7d22fSVladimir Kondratiev  * Due to a hardware issue,
252be7d22fSVladimir Kondratiev  * one has to read/write to/from NIC in 32-bit chunks;
262be7d22fSVladimir Kondratiev  * regular memcpy_fromio and siblings will
272be7d22fSVladimir Kondratiev  * not work on 64-bit platform - it uses 64-bit transactions
282be7d22fSVladimir Kondratiev  *
292be7d22fSVladimir Kondratiev  * Force 32-bit transactions to enable NIC on 64-bit platforms
302be7d22fSVladimir Kondratiev  *
312be7d22fSVladimir Kondratiev  * To avoid byte swap on big endian host, __raw_{read|write}l
322be7d22fSVladimir Kondratiev  * should be used - {read|write}l would swap bytes to provide
332be7d22fSVladimir Kondratiev  * little endian on PCI value in host endianness.
342be7d22fSVladimir Kondratiev  */
352be7d22fSVladimir Kondratiev void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
362be7d22fSVladimir Kondratiev 			  size_t count)
372be7d22fSVladimir Kondratiev {
382be7d22fSVladimir Kondratiev 	u32 *d = dst;
392be7d22fSVladimir Kondratiev 	const volatile u32 __iomem *s = src;
402be7d22fSVladimir Kondratiev 
412be7d22fSVladimir Kondratiev 	/* size_t is unsigned, if (count%4 != 0) it will wrap */
422be7d22fSVladimir Kondratiev 	for (count += 4; count > 4; count -= 4)
432be7d22fSVladimir Kondratiev 		*d++ = __raw_readl(s++);
442be7d22fSVladimir Kondratiev }
452be7d22fSVladimir Kondratiev 
462be7d22fSVladimir Kondratiev void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
472be7d22fSVladimir Kondratiev 			size_t count)
482be7d22fSVladimir Kondratiev {
492be7d22fSVladimir Kondratiev 	volatile u32 __iomem *d = dst;
502be7d22fSVladimir Kondratiev 	const u32 *s = src;
512be7d22fSVladimir Kondratiev 
522be7d22fSVladimir Kondratiev 	for (count += 4; count > 4; count -= 4)
532be7d22fSVladimir Kondratiev 		__raw_writel(*s++, d++);
542be7d22fSVladimir Kondratiev }
552be7d22fSVladimir Kondratiev 
562be7d22fSVladimir Kondratiev static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
572be7d22fSVladimir Kondratiev {
58b4490f42SVladimir Kondratiev 	uint i, cid;
592be7d22fSVladimir Kondratiev 	struct net_device *ndev = wil_to_ndev(wil);
602be7d22fSVladimir Kondratiev 
617743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "%s()\n", __func__);
622be7d22fSVladimir Kondratiev 
63b4490f42SVladimir Kondratiev 	for (cid = 0; cid < WIL6210_MAX_CID; cid++) {
64b4490f42SVladimir Kondratiev 		struct wil_sta_info *sta = &wil->sta[cid];
65b4490f42SVladimir Kondratiev 		for (i = 0; i < WIL_STA_TID_NUM; i++) {
66b4490f42SVladimir Kondratiev 			struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
67b4490f42SVladimir Kondratiev 			sta->tid_rx[i] = NULL;
68b4490f42SVladimir Kondratiev 			wil_tid_ampdu_rx_free(wil, r);
69b4490f42SVladimir Kondratiev 		}
70b4490f42SVladimir Kondratiev 	}
71b4490f42SVladimir Kondratiev 
722be7d22fSVladimir Kondratiev 	wil_link_off(wil);
73b338f74eSVladimir Kondratiev 	if (test_bit(wil_status_fwconnected, &wil->status)) {
742be7d22fSVladimir Kondratiev 		clear_bit(wil_status_fwconnected, &wil->status);
75b338f74eSVladimir Kondratiev 		cfg80211_disconnected(ndev,
76b338f74eSVladimir Kondratiev 				      WLAN_STATUS_UNSPECIFIED_FAILURE,
772be7d22fSVladimir Kondratiev 				      NULL, 0, GFP_KERNEL);
78b338f74eSVladimir Kondratiev 	} else if (test_bit(wil_status_fwconnecting, &wil->status)) {
792be7d22fSVladimir Kondratiev 		cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
802be7d22fSVladimir Kondratiev 					WLAN_STATUS_UNSPECIFIED_FAILURE,
812be7d22fSVladimir Kondratiev 					GFP_KERNEL);
822be7d22fSVladimir Kondratiev 	}
83b338f74eSVladimir Kondratiev 	clear_bit(wil_status_fwconnecting, &wil->status);
842be7d22fSVladimir Kondratiev 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
852be7d22fSVladimir Kondratiev 		wil_vring_fini_tx(wil, i);
86b98917d7SVladimir Kondratiev 
87b98917d7SVladimir Kondratiev 	clear_bit(wil_status_dontscan, &wil->status);
882be7d22fSVladimir Kondratiev }
892be7d22fSVladimir Kondratiev 
902be7d22fSVladimir Kondratiev static void wil_disconnect_worker(struct work_struct *work)
912be7d22fSVladimir Kondratiev {
922be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = container_of(work,
932be7d22fSVladimir Kondratiev 			struct wil6210_priv, disconnect_worker);
942be7d22fSVladimir Kondratiev 
952be7d22fSVladimir Kondratiev 	_wil6210_disconnect(wil, NULL);
962be7d22fSVladimir Kondratiev }
972be7d22fSVladimir Kondratiev 
982be7d22fSVladimir Kondratiev static void wil_connect_timer_fn(ulong x)
992be7d22fSVladimir Kondratiev {
1002be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = (void *)x;
1012be7d22fSVladimir Kondratiev 
1027743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "Connect timeout\n");
1032be7d22fSVladimir Kondratiev 
1042be7d22fSVladimir Kondratiev 	/* reschedule to thread context - disconnect won't
1052be7d22fSVladimir Kondratiev 	 * run from atomic context
1062be7d22fSVladimir Kondratiev 	 */
1072be7d22fSVladimir Kondratiev 	schedule_work(&wil->disconnect_worker);
1082be7d22fSVladimir Kondratiev }
1092be7d22fSVladimir Kondratiev 
1109a177384SVladimir Kondratiev static int wil_find_free_vring(struct wil6210_priv *wil)
1119a177384SVladimir Kondratiev {
1129a177384SVladimir Kondratiev 	int i;
1139a177384SVladimir Kondratiev 	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
1149a177384SVladimir Kondratiev 		if (!wil->vring_tx[i].va)
1159a177384SVladimir Kondratiev 			return i;
1169a177384SVladimir Kondratiev 	}
1179a177384SVladimir Kondratiev 	return -EINVAL;
1189a177384SVladimir Kondratiev }
1199a177384SVladimir Kondratiev 
120d81079f1SVladimir Kondratiev static void wil_connect_worker(struct work_struct *work)
121d81079f1SVladimir Kondratiev {
122d81079f1SVladimir Kondratiev 	int rc;
123d81079f1SVladimir Kondratiev 	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
124d81079f1SVladimir Kondratiev 						connect_worker);
125d81079f1SVladimir Kondratiev 	int cid = wil->pending_connect_cid;
1269a177384SVladimir Kondratiev 	int ringid = wil_find_free_vring(wil);
127d81079f1SVladimir Kondratiev 
128d81079f1SVladimir Kondratiev 	if (cid < 0) {
129d81079f1SVladimir Kondratiev 		wil_err(wil, "No connection pending\n");
130d81079f1SVladimir Kondratiev 		return;
131d81079f1SVladimir Kondratiev 	}
132d81079f1SVladimir Kondratiev 
133d81079f1SVladimir Kondratiev 	wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
134d81079f1SVladimir Kondratiev 
1359a177384SVladimir Kondratiev 	rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
136d81079f1SVladimir Kondratiev 	wil->pending_connect_cid = -1;
1373df2cd36SVladimir Kondratiev 	if (rc == 0) {
1383df2cd36SVladimir Kondratiev 		wil->sta[cid].status = wil_sta_connected;
139d81079f1SVladimir Kondratiev 		wil_link_on(wil);
1403df2cd36SVladimir Kondratiev 	} else {
1413df2cd36SVladimir Kondratiev 		wil->sta[cid].status = wil_sta_unused;
1423df2cd36SVladimir Kondratiev 	}
143d81079f1SVladimir Kondratiev }
144d81079f1SVladimir Kondratiev 
1452be7d22fSVladimir Kondratiev int wil_priv_init(struct wil6210_priv *wil)
1462be7d22fSVladimir Kondratiev {
1477743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "%s()\n", __func__);
1482be7d22fSVladimir Kondratiev 
1493df2cd36SVladimir Kondratiev 	memset(wil->sta, 0, sizeof(wil->sta));
1503df2cd36SVladimir Kondratiev 
1512be7d22fSVladimir Kondratiev 	mutex_init(&wil->mutex);
1522be7d22fSVladimir Kondratiev 	mutex_init(&wil->wmi_mutex);
1532be7d22fSVladimir Kondratiev 
1542be7d22fSVladimir Kondratiev 	init_completion(&wil->wmi_ready);
1552be7d22fSVladimir Kondratiev 
1562be7d22fSVladimir Kondratiev 	wil->pending_connect_cid = -1;
1572be7d22fSVladimir Kondratiev 	setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
1582be7d22fSVladimir Kondratiev 
159d81079f1SVladimir Kondratiev 	INIT_WORK(&wil->connect_worker, wil_connect_worker);
1602be7d22fSVladimir Kondratiev 	INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
1612be7d22fSVladimir Kondratiev 	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
1622be7d22fSVladimir Kondratiev 
1632be7d22fSVladimir Kondratiev 	INIT_LIST_HEAD(&wil->pending_wmi_ev);
1642be7d22fSVladimir Kondratiev 	spin_lock_init(&wil->wmi_ev_lock);
1652be7d22fSVladimir Kondratiev 
1662be7d22fSVladimir Kondratiev 	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
1672be7d22fSVladimir Kondratiev 	if (!wil->wmi_wq)
1682be7d22fSVladimir Kondratiev 		return -EAGAIN;
1692be7d22fSVladimir Kondratiev 
1702be7d22fSVladimir Kondratiev 	wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
1712be7d22fSVladimir Kondratiev 	if (!wil->wmi_wq_conn) {
1722be7d22fSVladimir Kondratiev 		destroy_workqueue(wil->wmi_wq);
1732be7d22fSVladimir Kondratiev 		return -EAGAIN;
1742be7d22fSVladimir Kondratiev 	}
1752be7d22fSVladimir Kondratiev 
1762be7d22fSVladimir Kondratiev 	return 0;
1772be7d22fSVladimir Kondratiev }
1782be7d22fSVladimir Kondratiev 
1792be7d22fSVladimir Kondratiev void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
1802be7d22fSVladimir Kondratiev {
1812be7d22fSVladimir Kondratiev 	del_timer_sync(&wil->connect_timer);
1822be7d22fSVladimir Kondratiev 	_wil6210_disconnect(wil, bssid);
1832be7d22fSVladimir Kondratiev }
1842be7d22fSVladimir Kondratiev 
1852be7d22fSVladimir Kondratiev void wil_priv_deinit(struct wil6210_priv *wil)
1862be7d22fSVladimir Kondratiev {
1872be7d22fSVladimir Kondratiev 	cancel_work_sync(&wil->disconnect_worker);
1882be7d22fSVladimir Kondratiev 	wil6210_disconnect(wil, NULL);
1892be7d22fSVladimir Kondratiev 	wmi_event_flush(wil);
1902be7d22fSVladimir Kondratiev 	destroy_workqueue(wil->wmi_wq_conn);
1912be7d22fSVladimir Kondratiev 	destroy_workqueue(wil->wmi_wq);
1922be7d22fSVladimir Kondratiev }
1932be7d22fSVladimir Kondratiev 
1942be7d22fSVladimir Kondratiev static void wil_target_reset(struct wil6210_priv *wil)
1952be7d22fSVladimir Kondratiev {
1967743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "Resetting...\n");
1972be7d22fSVladimir Kondratiev 
1982be7d22fSVladimir Kondratiev 	/* register write */
1992be7d22fSVladimir Kondratiev #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
2002be7d22fSVladimir Kondratiev 	/* register set = read, OR, write */
2012be7d22fSVladimir Kondratiev #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \
2022be7d22fSVladimir Kondratiev 		wil->csr + HOSTADDR(a))
2032be7d22fSVladimir Kondratiev 
2042be7d22fSVladimir Kondratiev 	/* hpal_perst_from_pad_src_n_mask */
2052be7d22fSVladimir Kondratiev 	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
2062be7d22fSVladimir Kondratiev 	/* car_perst_rst_src_n_mask */
2072be7d22fSVladimir Kondratiev 	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
2082be7d22fSVladimir Kondratiev 
2092be7d22fSVladimir Kondratiev 	W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
2102be7d22fSVladimir Kondratiev 	W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
2112be7d22fSVladimir Kondratiev 
2122be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
2132be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
2142be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
2152be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
2162be7d22fSVladimir Kondratiev 
2172be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
2182be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
2192be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
2202be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
2212be7d22fSVladimir Kondratiev 
2222be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
2232be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
2242be7d22fSVladimir Kondratiev 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
2252be7d22fSVladimir Kondratiev 
2267743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "Reset completed\n");
2272be7d22fSVladimir Kondratiev 
2282be7d22fSVladimir Kondratiev #undef W
2292be7d22fSVladimir Kondratiev #undef S
2302be7d22fSVladimir Kondratiev }
2312be7d22fSVladimir Kondratiev 
2322be7d22fSVladimir Kondratiev void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
2332be7d22fSVladimir Kondratiev {
2342be7d22fSVladimir Kondratiev 	le32_to_cpus(&r->base);
2352be7d22fSVladimir Kondratiev 	le16_to_cpus(&r->entry_size);
2362be7d22fSVladimir Kondratiev 	le16_to_cpus(&r->size);
2372be7d22fSVladimir Kondratiev 	le32_to_cpus(&r->tail);
2382be7d22fSVladimir Kondratiev 	le32_to_cpus(&r->head);
2392be7d22fSVladimir Kondratiev }
2402be7d22fSVladimir Kondratiev 
2412be7d22fSVladimir Kondratiev static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
2422be7d22fSVladimir Kondratiev {
2432be7d22fSVladimir Kondratiev 	ulong to = msecs_to_jiffies(1000);
2442be7d22fSVladimir Kondratiev 	ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
2452be7d22fSVladimir Kondratiev 	if (0 == left) {
2462be7d22fSVladimir Kondratiev 		wil_err(wil, "Firmware not ready\n");
2472be7d22fSVladimir Kondratiev 		return -ETIME;
2482be7d22fSVladimir Kondratiev 	} else {
2497743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "FW ready after %d ms\n",
2502be7d22fSVladimir Kondratiev 			     jiffies_to_msecs(to-left));
2512be7d22fSVladimir Kondratiev 	}
2522be7d22fSVladimir Kondratiev 	return 0;
2532be7d22fSVladimir Kondratiev }
2542be7d22fSVladimir Kondratiev 
2552be7d22fSVladimir Kondratiev /*
2562be7d22fSVladimir Kondratiev  * We reset all the structures, and we reset the UMAC.
2572be7d22fSVladimir Kondratiev  * After calling this routine, you're expected to reload
2582be7d22fSVladimir Kondratiev  * the firmware.
2592be7d22fSVladimir Kondratiev  */
2602be7d22fSVladimir Kondratiev int wil_reset(struct wil6210_priv *wil)
2612be7d22fSVladimir Kondratiev {
2622be7d22fSVladimir Kondratiev 	int rc;
2632be7d22fSVladimir Kondratiev 
2642be7d22fSVladimir Kondratiev 	cancel_work_sync(&wil->disconnect_worker);
2652be7d22fSVladimir Kondratiev 	wil6210_disconnect(wil, NULL);
2662be7d22fSVladimir Kondratiev 
2672be7d22fSVladimir Kondratiev 	wil6210_disable_irq(wil);
2682be7d22fSVladimir Kondratiev 	wil->status = 0;
2692be7d22fSVladimir Kondratiev 
270e08b5906SVladimir Kondratiev 	wmi_event_flush(wil);
271e08b5906SVladimir Kondratiev 
272e08b5906SVladimir Kondratiev 	flush_workqueue(wil->wmi_wq_conn);
273e08b5906SVladimir Kondratiev 	flush_workqueue(wil->wmi_wq);
274e08b5906SVladimir Kondratiev 
2752be7d22fSVladimir Kondratiev 	/* TODO: put MAC in reset */
2762be7d22fSVladimir Kondratiev 	wil_target_reset(wil);
2772be7d22fSVladimir Kondratiev 
2782be7d22fSVladimir Kondratiev 	/* init after reset */
2792be7d22fSVladimir Kondratiev 	wil->pending_connect_cid = -1;
28016735d02SWolfram Sang 	reinit_completion(&wil->wmi_ready);
2812be7d22fSVladimir Kondratiev 
2822be7d22fSVladimir Kondratiev 	/* TODO: release MAC reset */
2832be7d22fSVladimir Kondratiev 	wil6210_enable_irq(wil);
2842be7d22fSVladimir Kondratiev 
2852be7d22fSVladimir Kondratiev 	/* we just started MAC, wait for FW ready */
2862be7d22fSVladimir Kondratiev 	rc = wil_wait_for_fw_ready(wil);
2872be7d22fSVladimir Kondratiev 
2882be7d22fSVladimir Kondratiev 	return rc;
2892be7d22fSVladimir Kondratiev }
2902be7d22fSVladimir Kondratiev 
2912be7d22fSVladimir Kondratiev 
2922be7d22fSVladimir Kondratiev void wil_link_on(struct wil6210_priv *wil)
2932be7d22fSVladimir Kondratiev {
2942be7d22fSVladimir Kondratiev 	struct net_device *ndev = wil_to_ndev(wil);
2952be7d22fSVladimir Kondratiev 
2967743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "%s()\n", __func__);
2972be7d22fSVladimir Kondratiev 
2982be7d22fSVladimir Kondratiev 	netif_carrier_on(ndev);
2992be7d22fSVladimir Kondratiev 	netif_tx_wake_all_queues(ndev);
3002be7d22fSVladimir Kondratiev }
3012be7d22fSVladimir Kondratiev 
3022be7d22fSVladimir Kondratiev void wil_link_off(struct wil6210_priv *wil)
3032be7d22fSVladimir Kondratiev {
3042be7d22fSVladimir Kondratiev 	struct net_device *ndev = wil_to_ndev(wil);
3052be7d22fSVladimir Kondratiev 
3067743882dSVladimir Kondratiev 	wil_dbg_misc(wil, "%s()\n", __func__);
3072be7d22fSVladimir Kondratiev 
3082be7d22fSVladimir Kondratiev 	netif_tx_stop_all_queues(ndev);
3092be7d22fSVladimir Kondratiev 	netif_carrier_off(ndev);
3102be7d22fSVladimir Kondratiev }
3112be7d22fSVladimir Kondratiev 
3122be7d22fSVladimir Kondratiev static int __wil_up(struct wil6210_priv *wil)
3132be7d22fSVladimir Kondratiev {
3142be7d22fSVladimir Kondratiev 	struct net_device *ndev = wil_to_ndev(wil);
3152be7d22fSVladimir Kondratiev 	struct wireless_dev *wdev = wil->wdev;
3162be7d22fSVladimir Kondratiev 	int rc;
3172be7d22fSVladimir Kondratiev 
3182be7d22fSVladimir Kondratiev 	rc = wil_reset(wil);
3192be7d22fSVladimir Kondratiev 	if (rc)
3202be7d22fSVladimir Kondratiev 		return rc;
3212be7d22fSVladimir Kondratiev 
322e31b2562SVladimir Kondratiev 	/* Rx VRING. After MAC and beacon */
323e31b2562SVladimir Kondratiev 	rc = wil_rx_init(wil);
324e31b2562SVladimir Kondratiev 	if (rc)
325e31b2562SVladimir Kondratiev 		return rc;
326e31b2562SVladimir Kondratiev 
3272be7d22fSVladimir Kondratiev 	switch (wdev->iftype) {
3282be7d22fSVladimir Kondratiev 	case NL80211_IFTYPE_STATION:
3297743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "type: STATION\n");
3302be7d22fSVladimir Kondratiev 		ndev->type = ARPHRD_ETHER;
3312be7d22fSVladimir Kondratiev 		break;
3322be7d22fSVladimir Kondratiev 	case NL80211_IFTYPE_AP:
3337743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "type: AP\n");
3342be7d22fSVladimir Kondratiev 		ndev->type = ARPHRD_ETHER;
3352be7d22fSVladimir Kondratiev 		break;
3362be7d22fSVladimir Kondratiev 	case NL80211_IFTYPE_P2P_CLIENT:
3377743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "type: P2P_CLIENT\n");
3382be7d22fSVladimir Kondratiev 		ndev->type = ARPHRD_ETHER;
3392be7d22fSVladimir Kondratiev 		break;
3402be7d22fSVladimir Kondratiev 	case NL80211_IFTYPE_P2P_GO:
3417743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "type: P2P_GO\n");
3422be7d22fSVladimir Kondratiev 		ndev->type = ARPHRD_ETHER;
3432be7d22fSVladimir Kondratiev 		break;
3442be7d22fSVladimir Kondratiev 	case NL80211_IFTYPE_MONITOR:
3457743882dSVladimir Kondratiev 		wil_dbg_misc(wil, "type: Monitor\n");
3462be7d22fSVladimir Kondratiev 		ndev->type = ARPHRD_IEEE80211_RADIOTAP;
3472be7d22fSVladimir Kondratiev 		/* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
3482be7d22fSVladimir Kondratiev 		break;
3492be7d22fSVladimir Kondratiev 	default:
3502be7d22fSVladimir Kondratiev 		return -EOPNOTSUPP;
3512be7d22fSVladimir Kondratiev 	}
3522be7d22fSVladimir Kondratiev 
3532be7d22fSVladimir Kondratiev 	/* MAC address - pre-requisite for other commands */
3542be7d22fSVladimir Kondratiev 	wmi_set_mac_address(wil, ndev->dev_addr);
3552be7d22fSVladimir Kondratiev 
3562be7d22fSVladimir Kondratiev 
357e0287c4aSVladimir Kondratiev 	napi_enable(&wil->napi_rx);
358e0287c4aSVladimir Kondratiev 	napi_enable(&wil->napi_tx);
359e0287c4aSVladimir Kondratiev 
3602be7d22fSVladimir Kondratiev 	return 0;
3612be7d22fSVladimir Kondratiev }
3622be7d22fSVladimir Kondratiev 
3632be7d22fSVladimir Kondratiev int wil_up(struct wil6210_priv *wil)
3642be7d22fSVladimir Kondratiev {
3652be7d22fSVladimir Kondratiev 	int rc;
3662be7d22fSVladimir Kondratiev 
3672be7d22fSVladimir Kondratiev 	mutex_lock(&wil->mutex);
3682be7d22fSVladimir Kondratiev 	rc = __wil_up(wil);
3692be7d22fSVladimir Kondratiev 	mutex_unlock(&wil->mutex);
3702be7d22fSVladimir Kondratiev 
3712be7d22fSVladimir Kondratiev 	return rc;
3722be7d22fSVladimir Kondratiev }
3732be7d22fSVladimir Kondratiev 
3742be7d22fSVladimir Kondratiev static int __wil_down(struct wil6210_priv *wil)
3752be7d22fSVladimir Kondratiev {
376e0287c4aSVladimir Kondratiev 	napi_disable(&wil->napi_rx);
377e0287c4aSVladimir Kondratiev 	napi_disable(&wil->napi_tx);
378e0287c4aSVladimir Kondratiev 
3792be7d22fSVladimir Kondratiev 	if (wil->scan_request) {
3802be7d22fSVladimir Kondratiev 		cfg80211_scan_done(wil->scan_request, true);
3812be7d22fSVladimir Kondratiev 		wil->scan_request = NULL;
3822be7d22fSVladimir Kondratiev 	}
3832be7d22fSVladimir Kondratiev 
3842be7d22fSVladimir Kondratiev 	wil6210_disconnect(wil, NULL);
3852be7d22fSVladimir Kondratiev 	wil_rx_fini(wil);
3862be7d22fSVladimir Kondratiev 
3872be7d22fSVladimir Kondratiev 	return 0;
3882be7d22fSVladimir Kondratiev }
3892be7d22fSVladimir Kondratiev 
3902be7d22fSVladimir Kondratiev int wil_down(struct wil6210_priv *wil)
3912be7d22fSVladimir Kondratiev {
3922be7d22fSVladimir Kondratiev 	int rc;
3932be7d22fSVladimir Kondratiev 
3942be7d22fSVladimir Kondratiev 	mutex_lock(&wil->mutex);
3952be7d22fSVladimir Kondratiev 	rc = __wil_down(wil);
3962be7d22fSVladimir Kondratiev 	mutex_unlock(&wil->mutex);
3972be7d22fSVladimir Kondratiev 
3982be7d22fSVladimir Kondratiev 	return rc;
3992be7d22fSVladimir Kondratiev }
4003df2cd36SVladimir Kondratiev 
4013df2cd36SVladimir Kondratiev int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
4023df2cd36SVladimir Kondratiev {
4033df2cd36SVladimir Kondratiev 	int i;
4043df2cd36SVladimir Kondratiev 	int rc = -ENOENT;
4053df2cd36SVladimir Kondratiev 
4063df2cd36SVladimir Kondratiev 	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
4073df2cd36SVladimir Kondratiev 		if ((wil->sta[i].status != wil_sta_unused) &&
4083df2cd36SVladimir Kondratiev 		    (0 == memcmp(wil->sta[i].addr, mac, ETH_ALEN))) {
4093df2cd36SVladimir Kondratiev 			rc = i;
4103df2cd36SVladimir Kondratiev 			break;
4113df2cd36SVladimir Kondratiev 		}
4123df2cd36SVladimir Kondratiev 	}
4133df2cd36SVladimir Kondratiev 
4143df2cd36SVladimir Kondratiev 	return rc;
4153df2cd36SVladimir Kondratiev }
416