xref: /freebsd/sys/compat/linuxkpi/common/src/linux_80211_macops.c (revision f943454bfbd98ce49516c6ede8626b5f2602edc1)
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