16b4cac81SBjoern A. Zeeb /*- 2d9f59799SBjoern A. Zeeb * Copyright (c) 2021-2022 The FreeBSD Foundation 36b4cac81SBjoern A. Zeeb * 46b4cac81SBjoern A. Zeeb * This software was developed by Björn Zeeb under sponsorship from 56b4cac81SBjoern A. Zeeb * the FreeBSD Foundation. 66b4cac81SBjoern A. Zeeb * 76b4cac81SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 86b4cac81SBjoern A. Zeeb * modification, are permitted provided that the following conditions 96b4cac81SBjoern A. Zeeb * are met: 106b4cac81SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 116b4cac81SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 126b4cac81SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 136b4cac81SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 146b4cac81SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 156b4cac81SBjoern A. Zeeb * 166b4cac81SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176b4cac81SBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186b4cac81SBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196b4cac81SBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 206b4cac81SBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216b4cac81SBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226b4cac81SBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236b4cac81SBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246b4cac81SBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256b4cac81SBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266b4cac81SBjoern A. Zeeb * SUCH DAMAGE. 276b4cac81SBjoern A. Zeeb */ 286b4cac81SBjoern A. Zeeb 296b4cac81SBjoern A. Zeeb #include <sys/param.h> 306b4cac81SBjoern A. Zeeb #include <sys/types.h> 316b4cac81SBjoern A. Zeeb #include <sys/kernel.h> 326b4cac81SBjoern A. Zeeb #include <sys/errno.h> 336b4cac81SBjoern A. Zeeb 346b4cac81SBjoern A. Zeeb #define LINUXKPI_NET80211 356b4cac81SBjoern A. Zeeb #include <net/mac80211.h> 366b4cac81SBjoern A. Zeeb 376b4cac81SBjoern A. Zeeb #include "linux_80211.h" 386b4cac81SBjoern A. Zeeb 3964d3da00SBjoern A. Zeeb /* Could be a different tracing framework later. */ 4064d3da00SBjoern A. Zeeb #ifdef LINUXKPI_DEBUG_80211 4164d3da00SBjoern A. Zeeb #define LKPI_80211_TRACE_MO(fmt, ...) \ 4264d3da00SBjoern A. Zeeb if (linuxkpi_debug_80211 & D80211_TRACE_MO) \ 43e578e650SEd Maste printf("LKPI_80211_TRACE_MO %s:%d: %d %d %lu: " fmt "\n", \ 443206587aSBjoern A. Zeeb __func__, __LINE__, curcpu, curthread->td_tid, \ 4505674847SBjoern A. Zeeb jiffies, ##__VA_ARGS__) 4664d3da00SBjoern A. Zeeb #else 4764d3da00SBjoern A. Zeeb #define LKPI_80211_TRACE_MO(...) do { } while(0) 4864d3da00SBjoern A. Zeeb #endif 4964d3da00SBjoern A. Zeeb 506b4cac81SBjoern A. Zeeb int 516b4cac81SBjoern A. Zeeb lkpi_80211_mo_start(struct ieee80211_hw *hw) 526b4cac81SBjoern A. Zeeb { 536b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 546b4cac81SBjoern A. Zeeb int error; 556b4cac81SBjoern A. Zeeb 56897cf423SBjoern A. Zeeb lockdep_assert_wiphy(hw->wiphy); 57897cf423SBjoern A. Zeeb 586b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 596b4cac81SBjoern A. Zeeb if (lhw->ops->start == NULL) { 606b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 616b4cac81SBjoern A. Zeeb goto out; 626b4cac81SBjoern A. Zeeb } 636b4cac81SBjoern A. Zeeb 646b4cac81SBjoern A. Zeeb if ((lhw->sc_flags & LKPI_MAC80211_DRV_STARTED)) { 656b4cac81SBjoern A. Zeeb /* Trying to start twice is an error. */ 666b4cac81SBjoern A. Zeeb error = EEXIST; 676b4cac81SBjoern A. Zeeb goto out; 686b4cac81SBjoern A. Zeeb } 6964d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p", hw); 706b4cac81SBjoern A. Zeeb error = lhw->ops->start(hw); 716b4cac81SBjoern A. Zeeb if (error == 0) 726b4cac81SBjoern A. Zeeb lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED; 736b4cac81SBjoern A. Zeeb 746b4cac81SBjoern A. Zeeb out: 756b4cac81SBjoern A. Zeeb return (error); 766b4cac81SBjoern A. Zeeb } 776b4cac81SBjoern A. Zeeb 786b4cac81SBjoern A. Zeeb void 797b43f4d0SBjoern A. Zeeb lkpi_80211_mo_stop(struct ieee80211_hw *hw, bool suspend) 806b4cac81SBjoern A. Zeeb { 816b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 826b4cac81SBjoern A. Zeeb 836b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 846b4cac81SBjoern A. Zeeb if (lhw->ops->stop == NULL) 856b4cac81SBjoern A. Zeeb return; 866b4cac81SBjoern A. Zeeb 877b43f4d0SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p suspend %d", hw, suspend); 887b43f4d0SBjoern A. Zeeb lhw->ops->stop(hw, suspend); 896b4cac81SBjoern A. Zeeb lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED; 906b4cac81SBjoern A. Zeeb } 916b4cac81SBjoern A. Zeeb 926b4cac81SBjoern A. Zeeb int 93527687a9SBjoern A. Zeeb lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs) 94527687a9SBjoern A. Zeeb { 95527687a9SBjoern A. Zeeb struct lkpi_hw *lhw; 96527687a9SBjoern A. Zeeb int error; 97527687a9SBjoern A. Zeeb 98527687a9SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 99527687a9SBjoern A. Zeeb if (lhw->ops->get_antenna == NULL) { 100527687a9SBjoern A. Zeeb error = EOPNOTSUPP; 101527687a9SBjoern A. Zeeb goto out; 102527687a9SBjoern A. Zeeb } 103527687a9SBjoern A. Zeeb 10464d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p", hw); 105*76aed633SBjoern A. Zeeb LKPI_80211_TRACE_MO("TODO link/radio_idx"); 106*76aed633SBjoern A. Zeeb error = lhw->ops->get_antenna(hw, 0, txs, rxs); 107527687a9SBjoern A. Zeeb 108527687a9SBjoern A. Zeeb out: 109527687a9SBjoern A. Zeeb return (error); 110527687a9SBjoern A. Zeeb } 111527687a9SBjoern A. Zeeb 112527687a9SBjoern A. Zeeb int 1136b4cac81SBjoern A. Zeeb lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th) 1146b4cac81SBjoern A. Zeeb { 1156b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1166b4cac81SBjoern A. Zeeb int error; 1176b4cac81SBjoern A. Zeeb 1186b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 1196b4cac81SBjoern A. Zeeb if (lhw->ops->set_frag_threshold == NULL) { 1206b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 1216b4cac81SBjoern A. Zeeb goto out; 1226b4cac81SBjoern A. Zeeb } 1236b4cac81SBjoern A. Zeeb 12464d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th); 125*76aed633SBjoern A. Zeeb LKPI_80211_TRACE_MO("TODO link/radio_idx"); 126*76aed633SBjoern A. Zeeb error = lhw->ops->set_frag_threshold(hw, 0, frag_th); 1276b4cac81SBjoern A. Zeeb 1286b4cac81SBjoern A. Zeeb out: 1296b4cac81SBjoern A. Zeeb return (error); 1306b4cac81SBjoern A. Zeeb } 1316b4cac81SBjoern A. Zeeb 1326b4cac81SBjoern A. Zeeb int 1336b4cac81SBjoern A. Zeeb lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th) 1346b4cac81SBjoern A. Zeeb { 1356b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1366b4cac81SBjoern A. Zeeb int error; 1376b4cac81SBjoern A. Zeeb 1386b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 1396b4cac81SBjoern A. Zeeb if (lhw->ops->set_rts_threshold == NULL) { 1406b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 1416b4cac81SBjoern A. Zeeb goto out; 1426b4cac81SBjoern A. Zeeb } 1436b4cac81SBjoern A. Zeeb 14464d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th); 145*76aed633SBjoern A. Zeeb LKPI_80211_TRACE_MO("TODO link/radio_idx"); 146*76aed633SBjoern A. Zeeb error = lhw->ops->set_rts_threshold(hw, 0, rts_th); 1476b4cac81SBjoern A. Zeeb 1486b4cac81SBjoern A. Zeeb out: 1496b4cac81SBjoern A. Zeeb return (error); 1506b4cac81SBjoern A. Zeeb } 1516b4cac81SBjoern A. Zeeb 1526b4cac81SBjoern A. Zeeb 1536b4cac81SBjoern A. Zeeb int 1546b4cac81SBjoern A. Zeeb lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 1556b4cac81SBjoern A. Zeeb { 1566b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1576b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1586b4cac81SBjoern A. Zeeb int error; 1596b4cac81SBjoern A. Zeeb 1606b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 1616b4cac81SBjoern A. Zeeb if (lhw->ops->add_interface == NULL) { 1626b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 1636b4cac81SBjoern A. Zeeb goto out; 1646b4cac81SBjoern A. Zeeb } 1656b4cac81SBjoern A. Zeeb 1666b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 1676b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 1686b4cac81SBjoern A. Zeeb if (lvif->added_to_drv) { 1696b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 1706b4cac81SBjoern A. Zeeb /* Trying to add twice is an error. */ 1716b4cac81SBjoern A. Zeeb error = EEXIST; 1726b4cac81SBjoern A. Zeeb goto out; 1736b4cac81SBjoern A. Zeeb } 1746b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 1756b4cac81SBjoern A. Zeeb 17664d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 1776b4cac81SBjoern A. Zeeb error = lhw->ops->add_interface(hw, vif); 1786b4cac81SBjoern A. Zeeb if (error == 0) { 1796b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 1806b4cac81SBjoern A. Zeeb lvif->added_to_drv = true; 1816b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 1826b4cac81SBjoern A. Zeeb } 1836b4cac81SBjoern A. Zeeb 1846b4cac81SBjoern A. Zeeb out: 1856b4cac81SBjoern A. Zeeb return (error); 1866b4cac81SBjoern A. Zeeb } 1876b4cac81SBjoern A. Zeeb 1886b4cac81SBjoern A. Zeeb void 1896b4cac81SBjoern A. Zeeb lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 1906b4cac81SBjoern A. Zeeb { 1916b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 1926b4cac81SBjoern A. Zeeb struct lkpi_vif *lvif; 1936b4cac81SBjoern A. Zeeb 1946b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 1956b4cac81SBjoern A. Zeeb if (lhw->ops->remove_interface == NULL) 1966b4cac81SBjoern A. Zeeb return; 1976b4cac81SBjoern A. Zeeb 1986b4cac81SBjoern A. Zeeb lvif = VIF_TO_LVIF(vif); 1996b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 2006b4cac81SBjoern A. Zeeb if (!lvif->added_to_drv) { 2016b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 2026b4cac81SBjoern A. Zeeb return; 2036b4cac81SBjoern A. Zeeb } 2046b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 2056b4cac81SBjoern A. Zeeb 20664d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 2076b4cac81SBjoern A. Zeeb lhw->ops->remove_interface(hw, vif); 2086b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_LOCK(lvif); 2096b4cac81SBjoern A. Zeeb lvif->added_to_drv = false; 2106b4cac81SBjoern A. Zeeb LKPI_80211_LVIF_UNLOCK(lvif); 2116b4cac81SBjoern A. Zeeb } 2126b4cac81SBjoern A. Zeeb 2136b4cac81SBjoern A. Zeeb 2146b4cac81SBjoern A. Zeeb int 2156b4cac81SBjoern A. Zeeb lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 2166b4cac81SBjoern A. Zeeb struct ieee80211_scan_request *sr) 2176b4cac81SBjoern A. Zeeb { 2186b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2196b4cac81SBjoern A. Zeeb int error; 2206b4cac81SBjoern A. Zeeb 2213206587aSBjoern A. Zeeb /* 2223206587aSBjoern A. Zeeb * MUST NOT return EPERM as that is a "magic number 1" based on rtw88 2233206587aSBjoern A. Zeeb * driver indicating hw_scan is not supported despite the ops call 2243206587aSBjoern A. Zeeb * being available. 2253206587aSBjoern A. Zeeb */ 2263206587aSBjoern A. Zeeb 2276b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2286b4cac81SBjoern A. Zeeb if (lhw->ops->hw_scan == NULL) { 2293206587aSBjoern A. Zeeb /* Return magic number to use sw scan. */ 2303206587aSBjoern A. Zeeb error = 1; 2316b4cac81SBjoern A. Zeeb goto out; 2326b4cac81SBjoern A. Zeeb } 2336b4cac81SBjoern A. Zeeb 2343206587aSBjoern A. Zeeb LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr); 2356b4cac81SBjoern A. Zeeb error = lhw->ops->hw_scan(hw, vif, sr); 2363206587aSBjoern A. Zeeb LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error); 2376b4cac81SBjoern A. Zeeb 2386b4cac81SBjoern A. Zeeb out: 2396b4cac81SBjoern A. Zeeb return (error); 2406b4cac81SBjoern A. Zeeb } 2416b4cac81SBjoern A. Zeeb 2426b4cac81SBjoern A. Zeeb void 2436b4cac81SBjoern A. Zeeb lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 2446b4cac81SBjoern A. Zeeb { 2456b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2466b4cac81SBjoern A. Zeeb 2476b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2486b4cac81SBjoern A. Zeeb if (lhw->ops->cancel_hw_scan == NULL) 2496b4cac81SBjoern A. Zeeb return; 2506b4cac81SBjoern A. Zeeb 25164d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 2526b4cac81SBjoern A. Zeeb lhw->ops->cancel_hw_scan(hw, vif); 2536b4cac81SBjoern A. Zeeb } 2546b4cac81SBjoern A. Zeeb 2556b4cac81SBjoern A. Zeeb void 2566b4cac81SBjoern A. Zeeb lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 2576b4cac81SBjoern A. Zeeb { 2586b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2596b4cac81SBjoern A. Zeeb 2606b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2616b4cac81SBjoern A. Zeeb if (lhw->ops->sw_scan_complete == NULL) 2626b4cac81SBjoern A. Zeeb return; 2636b4cac81SBjoern A. Zeeb 26464d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 2656b4cac81SBjoern A. Zeeb lhw->ops->sw_scan_complete(hw, vif); 266a486fbbdSBjoern A. Zeeb lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; 2676b4cac81SBjoern A. Zeeb } 2686b4cac81SBjoern A. Zeeb 2696b4cac81SBjoern A. Zeeb void 2706b4cac81SBjoern A. Zeeb lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 2716b4cac81SBjoern A. Zeeb const u8 *addr) 2726b4cac81SBjoern A. Zeeb { 2736b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2746b4cac81SBjoern A. Zeeb 2756b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2766b4cac81SBjoern A. Zeeb if (lhw->ops->sw_scan_start == NULL) 2776b4cac81SBjoern A. Zeeb return; 2786b4cac81SBjoern A. Zeeb 27964d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif); 2806b4cac81SBjoern A. Zeeb lhw->ops->sw_scan_start(hw, vif, addr); 2816b4cac81SBjoern A. Zeeb } 2826b4cac81SBjoern A. Zeeb 2836b4cac81SBjoern A. Zeeb 2846b4cac81SBjoern A. Zeeb /* 2856b4cac81SBjoern A. Zeeb * We keep the Linux type here; it really is an uintptr_t. 2866b4cac81SBjoern A. Zeeb */ 2876b4cac81SBjoern A. Zeeb u64 2886b4cac81SBjoern A. Zeeb lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw, 2896b4cac81SBjoern A. Zeeb struct netdev_hw_addr_list *mc_list) 2906b4cac81SBjoern A. Zeeb { 2916b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 2926b4cac81SBjoern A. Zeeb u64 ptr; 2936b4cac81SBjoern A. Zeeb 2946b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 2956b4cac81SBjoern A. Zeeb if (lhw->ops->prepare_multicast == NULL) 2966b4cac81SBjoern A. Zeeb return (0); 2976b4cac81SBjoern A. Zeeb 29864d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list); 2996b4cac81SBjoern A. Zeeb ptr = lhw->ops->prepare_multicast(hw, mc_list); 3006b4cac81SBjoern A. Zeeb return (ptr); 3016b4cac81SBjoern A. Zeeb } 3026b4cac81SBjoern A. Zeeb 3036b4cac81SBjoern A. Zeeb void 3046b4cac81SBjoern A. Zeeb lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, 3056b4cac81SBjoern A. Zeeb unsigned int *total_flags, u64 mc_ptr) 3066b4cac81SBjoern A. Zeeb { 3076b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3086b4cac81SBjoern A. Zeeb 3096b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3106b4cac81SBjoern A. Zeeb if (lhw->ops->configure_filter == NULL) 3116b4cac81SBjoern A. Zeeb return; 3126b4cac81SBjoern A. Zeeb 31364d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr); 3146b4cac81SBjoern A. Zeeb lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr); 3156b4cac81SBjoern A. Zeeb } 3166b4cac81SBjoern A. Zeeb 3176b4cac81SBjoern A. Zeeb 3186b4cac81SBjoern A. Zeeb /* 3196b4cac81SBjoern A. Zeeb * So far we only called sta_{add,remove} as an alternative to sta_state. 320d9f59799SBjoern A. Zeeb * Let's keep the implementation simpler and hide sta_{add,remove} under the 3216b4cac81SBjoern A. Zeeb * hood here calling them if state_state is not available from mo_sta_state. 3226b4cac81SBjoern A. Zeeb */ 3236b4cac81SBjoern A. Zeeb static int 3246b4cac81SBjoern A. Zeeb lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 3256b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta) 3266b4cac81SBjoern A. Zeeb { 3276b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3286b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 3296b4cac81SBjoern A. Zeeb int error; 3306b4cac81SBjoern A. Zeeb 3316b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3326b4cac81SBjoern A. Zeeb if (lhw->ops->sta_add == NULL) { 3336b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 3346b4cac81SBjoern A. Zeeb goto out; 3356b4cac81SBjoern A. Zeeb } 3366b4cac81SBjoern A. Zeeb 3376b4cac81SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 3386b4cac81SBjoern A. Zeeb if (lsta->added_to_drv) { 3396b4cac81SBjoern A. Zeeb error = EEXIST; 3406b4cac81SBjoern A. Zeeb goto out; 3416b4cac81SBjoern A. Zeeb } 3426b4cac81SBjoern A. Zeeb 34364d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 3446b4cac81SBjoern A. Zeeb error = lhw->ops->sta_add(hw, vif, sta); 3456b4cac81SBjoern A. Zeeb if (error == 0) 3466b4cac81SBjoern A. Zeeb lsta->added_to_drv = true; 3476b4cac81SBjoern A. Zeeb 3486b4cac81SBjoern A. Zeeb out: 3496b4cac81SBjoern A. Zeeb return error; 3506b4cac81SBjoern A. Zeeb } 3516b4cac81SBjoern A. Zeeb 3526b4cac81SBjoern A. Zeeb static int 3536b4cac81SBjoern A. Zeeb lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 3546b4cac81SBjoern A. Zeeb struct ieee80211_sta *sta) 3556b4cac81SBjoern A. Zeeb { 3566b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 3576b4cac81SBjoern A. Zeeb struct lkpi_sta *lsta; 3586b4cac81SBjoern A. Zeeb int error; 3596b4cac81SBjoern A. Zeeb 3606b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 3616b4cac81SBjoern A. Zeeb if (lhw->ops->sta_remove == NULL) { 3626b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 3636b4cac81SBjoern A. Zeeb goto out; 3646b4cac81SBjoern A. Zeeb } 3656b4cac81SBjoern A. Zeeb 3666b4cac81SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 3676b4cac81SBjoern A. Zeeb if (!lsta->added_to_drv) { 3686b4cac81SBjoern A. Zeeb /* If we never added the sta, do not complain on cleanup. */ 3696b4cac81SBjoern A. Zeeb error = 0; 3706b4cac81SBjoern A. Zeeb goto out; 3716b4cac81SBjoern A. Zeeb } 3726b4cac81SBjoern A. Zeeb 37364d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 3746b4cac81SBjoern A. Zeeb error = lhw->ops->sta_remove(hw, vif, sta); 3756b4cac81SBjoern A. Zeeb if (error == 0) 3766b4cac81SBjoern A. Zeeb lsta->added_to_drv = false; 3776b4cac81SBjoern A. Zeeb 3786b4cac81SBjoern A. Zeeb out: 3796b4cac81SBjoern A. Zeeb return error; 3806b4cac81SBjoern A. Zeeb } 3816b4cac81SBjoern A. Zeeb 3826b4cac81SBjoern A. Zeeb int 3836b4cac81SBjoern A. Zeeb lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 384e7fe0373SBjoern A. Zeeb struct lkpi_sta *lsta, enum ieee80211_sta_state nstate) 3856b4cac81SBjoern A. Zeeb { 3866b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 387e7fe0373SBjoern A. Zeeb struct ieee80211_sta *sta; 3886b4cac81SBjoern A. Zeeb int error; 3896b4cac81SBjoern A. Zeeb 3906b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 391e7fe0373SBjoern A. Zeeb sta = LSTA_TO_STA(lsta); 3926b4cac81SBjoern A. Zeeb if (lhw->ops->sta_state != NULL) { 39364d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate); 3946b4cac81SBjoern A. Zeeb error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate); 3956b4cac81SBjoern A. Zeeb if (error == 0) { 3966b4cac81SBjoern A. Zeeb if (nstate == IEEE80211_STA_NOTEXIST) 3976b4cac81SBjoern A. Zeeb lsta->added_to_drv = false; 3986b4cac81SBjoern A. Zeeb else 3996b4cac81SBjoern A. Zeeb lsta->added_to_drv = true; 4006b4cac81SBjoern A. Zeeb lsta->state = nstate; 4016b4cac81SBjoern A. Zeeb } 4026b4cac81SBjoern A. Zeeb goto out; 4036b4cac81SBjoern A. Zeeb } 4046b4cac81SBjoern A. Zeeb 4056b4cac81SBjoern A. Zeeb /* XXX-BZ is the change state AUTH or ASSOC here? */ 406878fb1e5SBjoern A. Zeeb if (lsta->state < IEEE80211_STA_ASSOC && nstate == IEEE80211_STA_ASSOC) { 4076b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_add(hw, vif, sta); 408878fb1e5SBjoern A. Zeeb if (error == 0) 409878fb1e5SBjoern A. Zeeb lsta->added_to_drv = true; 410878fb1e5SBjoern A. Zeeb } else if (lsta->state >= IEEE80211_STA_ASSOC && 411878fb1e5SBjoern A. Zeeb nstate < IEEE80211_STA_ASSOC) { 4126b4cac81SBjoern A. Zeeb error = lkpi_80211_mo_sta_remove(hw, vif, sta); 413878fb1e5SBjoern A. Zeeb if (error == 0) 414878fb1e5SBjoern A. Zeeb lsta->added_to_drv = false; 415878fb1e5SBjoern A. Zeeb } else 4166b4cac81SBjoern A. Zeeb /* Nothing to do. */ 4176b4cac81SBjoern A. Zeeb error = 0; 418878fb1e5SBjoern A. Zeeb if (error == 0) 419878fb1e5SBjoern A. Zeeb lsta->state = nstate; 4206b4cac81SBjoern A. Zeeb 4216b4cac81SBjoern A. Zeeb out: 4226b4cac81SBjoern A. Zeeb /* XXX-BZ should we manage state in here? */ 4236b4cac81SBjoern A. Zeeb return (error); 4246b4cac81SBjoern A. Zeeb } 4256b4cac81SBjoern A. Zeeb 4266b4cac81SBjoern A. Zeeb int 4276b4cac81SBjoern A. Zeeb lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed) 4286b4cac81SBjoern A. Zeeb { 4296b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 4306b4cac81SBjoern A. Zeeb int error; 4316b4cac81SBjoern A. Zeeb 4326b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 4336b4cac81SBjoern A. Zeeb if (lhw->ops->config == NULL) { 4346b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 4356b4cac81SBjoern A. Zeeb goto out; 4366b4cac81SBjoern A. Zeeb } 4376b4cac81SBjoern A. Zeeb 43864d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed); 439*76aed633SBjoern A. Zeeb LKPI_80211_TRACE_MO("TODO link/radio_idx"); 440*76aed633SBjoern A. Zeeb error = lhw->ops->config(hw, 0, changed); 4416b4cac81SBjoern A. Zeeb 4426b4cac81SBjoern A. Zeeb out: 4436b4cac81SBjoern A. Zeeb return (error); 4446b4cac81SBjoern A. Zeeb } 4456b4cac81SBjoern A. Zeeb 4466b4cac81SBjoern A. Zeeb 4476b4cac81SBjoern A. Zeeb int 4486b4cac81SBjoern A. Zeeb lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 44968541546SBjoern A. Zeeb struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf) 4506b4cac81SBjoern A. Zeeb { 4516b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 4526b4cac81SBjoern A. Zeeb int error; 4536b4cac81SBjoern A. Zeeb 4546b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 4556b4cac81SBjoern A. Zeeb if (lhw->ops->assign_vif_chanctx == NULL) { 4566b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 4576b4cac81SBjoern A. Zeeb goto out; 4586b4cac81SBjoern A. Zeeb } 4596b4cac81SBjoern A. Zeeb 46068541546SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p", 46168541546SBjoern A. Zeeb hw, vif, conf, chanctx_conf); 46268541546SBjoern A. Zeeb error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf); 4636b4cac81SBjoern A. Zeeb if (error == 0) 46411604b2aSBjoern A. Zeeb vif->bss_conf.chanctx_conf = chanctx_conf; 4656b4cac81SBjoern A. Zeeb 4666b4cac81SBjoern A. Zeeb out: 4676b4cac81SBjoern A. Zeeb return (error); 4686b4cac81SBjoern A. Zeeb } 4696b4cac81SBjoern A. Zeeb 4706b4cac81SBjoern A. Zeeb void 4716b4cac81SBjoern A. Zeeb lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 472231168c7SBjoern A. Zeeb struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf) 4736b4cac81SBjoern A. Zeeb { 4746b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 4756b4cac81SBjoern A. Zeeb 476231168c7SBjoern A. Zeeb might_sleep(); 477231168c7SBjoern A. Zeeb lockdep_assert_wiphy(hw->wiphy); 478231168c7SBjoern A. Zeeb 4796b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 4806b4cac81SBjoern A. Zeeb if (lhw->ops->unassign_vif_chanctx == NULL) 4816b4cac81SBjoern A. Zeeb return; 4826b4cac81SBjoern A. Zeeb 483231168c7SBjoern A. Zeeb if (chanctx_conf == NULL) 4846b4cac81SBjoern A. Zeeb return; 4856b4cac81SBjoern A. Zeeb 48668541546SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p", 487231168c7SBjoern A. Zeeb hw, vif, conf, chanctx_conf); 488231168c7SBjoern A. Zeeb lhw->ops->unassign_vif_chanctx(hw, vif, conf, chanctx_conf); 4896b4cac81SBjoern A. Zeeb } 4906b4cac81SBjoern A. Zeeb 4916b4cac81SBjoern A. Zeeb 4926b4cac81SBjoern A. Zeeb int 4936b4cac81SBjoern A. Zeeb lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw, 4946b4cac81SBjoern A. Zeeb struct ieee80211_chanctx_conf *chanctx_conf) 4956b4cac81SBjoern A. Zeeb { 4966b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 497c5e25798SBjoern A. Zeeb struct lkpi_chanctx *lchanctx; 4986b4cac81SBjoern A. Zeeb int error; 4996b4cac81SBjoern A. Zeeb 5006b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 5016b4cac81SBjoern A. Zeeb if (lhw->ops->add_chanctx == NULL) { 5026b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 5036b4cac81SBjoern A. Zeeb goto out; 5046b4cac81SBjoern A. Zeeb } 5056b4cac81SBjoern A. Zeeb 50664d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf); 5076b4cac81SBjoern A. Zeeb error = lhw->ops->add_chanctx(hw, chanctx_conf); 508c5e25798SBjoern A. Zeeb if (error == 0) { 509c5e25798SBjoern A. Zeeb lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf); 510c5e25798SBjoern A. Zeeb lchanctx->added_to_drv = true; 511c5e25798SBjoern A. Zeeb } 5126b4cac81SBjoern A. Zeeb 5136b4cac81SBjoern A. Zeeb out: 5146b4cac81SBjoern A. Zeeb return (error); 5156b4cac81SBjoern A. Zeeb } 5166b4cac81SBjoern A. Zeeb 5176b4cac81SBjoern A. Zeeb void 5186b4cac81SBjoern A. Zeeb lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw, 5196b4cac81SBjoern A. Zeeb struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed) 5206b4cac81SBjoern A. Zeeb { 5216b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 5226b4cac81SBjoern A. Zeeb 5236b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 5246b4cac81SBjoern A. Zeeb if (lhw->ops->change_chanctx == NULL) 5256b4cac81SBjoern A. Zeeb return; 5266b4cac81SBjoern A. Zeeb 52764d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed); 5286b4cac81SBjoern A. Zeeb lhw->ops->change_chanctx(hw, chanctx_conf, changed); 5296b4cac81SBjoern A. Zeeb } 5306b4cac81SBjoern A. Zeeb 5316b4cac81SBjoern A. Zeeb void 5326b4cac81SBjoern A. Zeeb lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw, 5336b4cac81SBjoern A. Zeeb struct ieee80211_chanctx_conf *chanctx_conf) 5346b4cac81SBjoern A. Zeeb { 5356b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 536c5e25798SBjoern A. Zeeb struct lkpi_chanctx *lchanctx; 5376b4cac81SBjoern A. Zeeb 5386b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 5396b4cac81SBjoern A. Zeeb if (lhw->ops->remove_chanctx == NULL) 5406b4cac81SBjoern A. Zeeb return; 5416b4cac81SBjoern A. Zeeb 54264d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf); 5436b4cac81SBjoern A. Zeeb lhw->ops->remove_chanctx(hw, chanctx_conf); 544c5e25798SBjoern A. Zeeb lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf); 545c5e25798SBjoern A. Zeeb lchanctx->added_to_drv = false; 5466b4cac81SBjoern A. Zeeb } 5476b4cac81SBjoern A. Zeeb 5486b4cac81SBjoern A. Zeeb void 5496b4cac81SBjoern A. Zeeb lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 550467d3e2eSBjoern A. Zeeb struct ieee80211_bss_conf *conf, uint64_t changed) 5516b4cac81SBjoern A. Zeeb { 5526b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 5536b4cac81SBjoern A. Zeeb 5546b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 555727f88f2SBjoern A. Zeeb if (lhw->ops->link_info_changed == NULL && 556727f88f2SBjoern A. Zeeb lhw->ops->bss_info_changed == NULL) 5576b4cac81SBjoern A. Zeeb return; 5586b4cac81SBjoern A. Zeeb 559ae8c3b65SBjoern A. Zeeb if (changed == 0) 560ae8c3b65SBjoern A. Zeeb return; 561ae8c3b65SBjoern A. Zeeb 56264d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed); 563727f88f2SBjoern A. Zeeb if (lhw->ops->link_info_changed != NULL) 564727f88f2SBjoern A. Zeeb lhw->ops->link_info_changed(hw, vif, conf, changed); 565727f88f2SBjoern A. Zeeb else 5666b4cac81SBjoern A. Zeeb lhw->ops->bss_info_changed(hw, vif, conf, changed); 5676b4cac81SBjoern A. Zeeb } 5686b4cac81SBjoern A. Zeeb 5696b4cac81SBjoern A. Zeeb int 5706b4cac81SBjoern A. Zeeb lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 57168541546SBjoern A. Zeeb uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp) 5726b4cac81SBjoern A. Zeeb { 5736b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 5746b4cac81SBjoern A. Zeeb int error; 5756b4cac81SBjoern A. Zeeb 5766b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 5776b4cac81SBjoern A. Zeeb if (lhw->ops->conf_tx == NULL) { 5786b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 5796b4cac81SBjoern A. Zeeb goto out; 5806b4cac81SBjoern A. Zeeb } 5816b4cac81SBjoern A. Zeeb 58268541546SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p", 58368541546SBjoern A. Zeeb hw, vif, link_id, ac, txqp); 58468541546SBjoern A. Zeeb error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp); 5856b4cac81SBjoern A. Zeeb 5866b4cac81SBjoern A. Zeeb out: 5876b4cac81SBjoern A. Zeeb return (error); 5886b4cac81SBjoern A. Zeeb } 5896b4cac81SBjoern A. Zeeb 5906b4cac81SBjoern A. Zeeb void 5916b4cac81SBjoern A. Zeeb lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 5926b4cac81SBjoern A. Zeeb uint32_t nqueues, bool drop) 5936b4cac81SBjoern A. Zeeb { 5946b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 5956b4cac81SBjoern A. Zeeb 5966b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 5976b4cac81SBjoern A. Zeeb if (lhw->ops->flush == NULL) 5986b4cac81SBjoern A. Zeeb return; 5996b4cac81SBjoern A. Zeeb 60064d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop); 6016b4cac81SBjoern A. Zeeb lhw->ops->flush(hw, vif, nqueues, drop); 6026b4cac81SBjoern A. Zeeb } 6036b4cac81SBjoern A. Zeeb 6046b4cac81SBjoern A. Zeeb void 6056b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 6066b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info *txinfo) 6076b4cac81SBjoern A. Zeeb { 6086b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6096b4cac81SBjoern A. Zeeb 6106b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6116b4cac81SBjoern A. Zeeb if (lhw->ops->mgd_prepare_tx == NULL) 6126b4cac81SBjoern A. Zeeb return; 6136b4cac81SBjoern A. Zeeb 61464d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo); 6156b4cac81SBjoern A. Zeeb lhw->ops->mgd_prepare_tx(hw, vif, txinfo); 6166b4cac81SBjoern A. Zeeb } 6176b4cac81SBjoern A. Zeeb 6186b4cac81SBjoern A. Zeeb void 6196b4cac81SBjoern A. Zeeb lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 6206b4cac81SBjoern A. Zeeb struct ieee80211_prep_tx_info *txinfo) 6216b4cac81SBjoern A. Zeeb { 6226b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6236b4cac81SBjoern A. Zeeb 6246b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6256b4cac81SBjoern A. Zeeb if (lhw->ops->mgd_complete_tx == NULL) 6266b4cac81SBjoern A. Zeeb return; 6276b4cac81SBjoern A. Zeeb 62864d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo); 6296b4cac81SBjoern A. Zeeb lhw->ops->mgd_complete_tx(hw, vif, txinfo); 6306b4cac81SBjoern A. Zeeb } 6316b4cac81SBjoern A. Zeeb 6326b4cac81SBjoern A. Zeeb void 6336b4cac81SBjoern A. Zeeb lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl, 6346b4cac81SBjoern A. Zeeb struct sk_buff *skb) 6356b4cac81SBjoern A. Zeeb { 6366b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6376b4cac81SBjoern A. Zeeb 6386b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6396b4cac81SBjoern A. Zeeb if (lhw->ops->tx == NULL) 6406b4cac81SBjoern A. Zeeb return; 6416b4cac81SBjoern A. Zeeb 64264d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb); 6436b4cac81SBjoern A. Zeeb lhw->ops->tx(hw, txctrl, skb); 6446b4cac81SBjoern A. Zeeb } 6456b4cac81SBjoern A. Zeeb 6466b4cac81SBjoern A. Zeeb void 6476b4cac81SBjoern A. Zeeb lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) 6486b4cac81SBjoern A. Zeeb { 6496b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6506b4cac81SBjoern A. Zeeb 6516b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6526b4cac81SBjoern A. Zeeb if (lhw->ops->wake_tx_queue == NULL) 6536b4cac81SBjoern A. Zeeb return; 6546b4cac81SBjoern A. Zeeb 65564d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq); 6566b4cac81SBjoern A. Zeeb lhw->ops->wake_tx_queue(hw, txq); 6576b4cac81SBjoern A. Zeeb } 6586b4cac81SBjoern A. Zeeb 6596b4cac81SBjoern A. Zeeb void 6606b4cac81SBjoern A. Zeeb lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw) 6616b4cac81SBjoern A. Zeeb { 6626b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6636b4cac81SBjoern A. Zeeb 6646b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6656b4cac81SBjoern A. Zeeb if (lhw->ops->sync_rx_queues == NULL) 6666b4cac81SBjoern A. Zeeb return; 6676b4cac81SBjoern A. Zeeb 66864d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p", hw); 6696b4cac81SBjoern A. Zeeb lhw->ops->sync_rx_queues(hw); 6706b4cac81SBjoern A. Zeeb } 6716b4cac81SBjoern A. Zeeb 6726b4cac81SBjoern A. Zeeb void 6736b4cac81SBjoern A. Zeeb lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw, 6746b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta) 6756b4cac81SBjoern A. Zeeb { 6766b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6776b4cac81SBjoern A. Zeeb 6786b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6796b4cac81SBjoern A. Zeeb if (lhw->ops->sta_pre_rcu_remove == NULL) 6806b4cac81SBjoern A. Zeeb return; 6816b4cac81SBjoern A. Zeeb 68264d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta); 6836b4cac81SBjoern A. Zeeb lhw->ops->sta_pre_rcu_remove(hw, vif, sta); 6846b4cac81SBjoern A. Zeeb } 6856b4cac81SBjoern A. Zeeb 6866b4cac81SBjoern A. Zeeb int 6876b4cac81SBjoern A. Zeeb lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 6886b4cac81SBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta, 6896b4cac81SBjoern A. Zeeb struct ieee80211_key_conf *kc) 6906b4cac81SBjoern A. Zeeb { 6916b4cac81SBjoern A. Zeeb struct lkpi_hw *lhw; 6926b4cac81SBjoern A. Zeeb int error; 6936b4cac81SBjoern A. Zeeb 69411db70b6SBjoern A. Zeeb lockdep_assert_wiphy(hw->wiphy); 69511db70b6SBjoern A. Zeeb 6966b4cac81SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 6976b4cac81SBjoern A. Zeeb if (lhw->ops->set_key == NULL) { 6986b4cac81SBjoern A. Zeeb error = EOPNOTSUPP; 6996b4cac81SBjoern A. Zeeb goto out; 7006b4cac81SBjoern A. Zeeb } 7016b4cac81SBjoern A. Zeeb 70264d3da00SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc); 7036b4cac81SBjoern A. Zeeb error = lhw->ops->set_key(hw, cmd, vif, sta, kc); 7046b4cac81SBjoern A. Zeeb 7056b4cac81SBjoern A. Zeeb out: 7066b4cac81SBjoern A. Zeeb return (error); 7076b4cac81SBjoern A. Zeeb } 7089fb91463SBjoern A. Zeeb 7099fb91463SBjoern A. Zeeb int 7109fb91463SBjoern A. Zeeb lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 7119fb91463SBjoern A. Zeeb struct ieee80211_ampdu_params *params) 7129fb91463SBjoern A. Zeeb { 7139fb91463SBjoern A. Zeeb struct lkpi_hw *lhw; 7149fb91463SBjoern A. Zeeb int error; 7159fb91463SBjoern A. Zeeb 7169fb91463SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 7179fb91463SBjoern A. Zeeb if (lhw->ops->ampdu_action == NULL) { 7189fb91463SBjoern A. Zeeb error = EOPNOTSUPP; 7199fb91463SBjoern A. Zeeb goto out; 7209fb91463SBjoern A. Zeeb } 7219fb91463SBjoern A. Zeeb 7229fb91463SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }", 7239fb91463SBjoern A. Zeeb hw, vif, params, params->sta, params->action, params->buf_size, 7249fb91463SBjoern A. Zeeb params->timeout, params->ssn, params->tid, params->amsdu); 7259fb91463SBjoern A. Zeeb error = lhw->ops->ampdu_action(hw, vif, params); 7269fb91463SBjoern A. Zeeb 7279fb91463SBjoern A. Zeeb out: 7289fb91463SBjoern A. Zeeb return (error); 7299fb91463SBjoern A. Zeeb } 73040839418SBjoern A. Zeeb 73140839418SBjoern A. Zeeb int 73240839418SBjoern A. Zeeb lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 73340839418SBjoern A. Zeeb struct ieee80211_sta *sta, struct station_info *sinfo) 73440839418SBjoern A. Zeeb { 73540839418SBjoern A. Zeeb struct lkpi_hw *lhw; 73640839418SBjoern A. Zeeb struct lkpi_sta *lsta; 73740839418SBjoern A. Zeeb int error; 73840839418SBjoern A. Zeeb 73940839418SBjoern A. Zeeb lhw = HW_TO_LHW(hw); 74040839418SBjoern A. Zeeb if (lhw->ops->sta_statistics == NULL) { 74140839418SBjoern A. Zeeb error = EOPNOTSUPP; 74240839418SBjoern A. Zeeb goto out; 74340839418SBjoern A. Zeeb } 74440839418SBjoern A. Zeeb 74540839418SBjoern A. Zeeb lsta = STA_TO_LSTA(sta); 74640839418SBjoern A. Zeeb if (!lsta->added_to_drv) { 74740839418SBjoern A. Zeeb error = EEXIST; 74840839418SBjoern A. Zeeb goto out; 74940839418SBjoern A. Zeeb } 75040839418SBjoern A. Zeeb 75140839418SBjoern A. Zeeb lockdep_assert_wiphy(hw->wiphy); 75240839418SBjoern A. Zeeb 75340839418SBjoern A. Zeeb LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo); 75440839418SBjoern A. Zeeb lhw->ops->sta_statistics(hw, vif, sta, sinfo); 75540839418SBjoern A. Zeeb error = 0; 75640839418SBjoern A. Zeeb 75740839418SBjoern A. Zeeb out: 75840839418SBjoern A. Zeeb return (error); 75940839418SBjoern A. Zeeb } 760