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