1 /*-
2 * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #include "opt_wlan.h"
29
30 #include <sys/param.h>
31 #include <sys/lock.h>
32 #include <sys/mutex.h>
33 #include <sys/mbuf.h>
34 #include <sys/kernel.h>
35 #include <sys/socket.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 #include <sys/taskqueue.h>
40 #include <sys/bus.h>
41 #include <sys/endian.h>
42 #include <sys/linker.h>
43
44 #include <net/if.h>
45 #include <net/ethernet.h>
46 #include <net/if_media.h>
47
48 #include <net80211/ieee80211_var.h>
49 #include <net80211/ieee80211_radiotap.h>
50
51 #include <dev/rtwn/if_rtwnvar.h>
52 #include <dev/rtwn/if_rtwn_debug.h>
53
54 #include <dev/rtwn/usb/rtwn_usb_var.h>
55
56 #include <dev/rtwn/rtl8812a/r12a_var.h>
57
58 #include <dev/rtwn/rtl8821a/usb/r21au.h>
59 #include <dev/rtwn/rtl8821a/usb/r21au_reg.h>
60
61 #define R21AU_RADAR_CHECK_PERIOD (2 * hz)
62
63 static void
r21au_dfs_radar_disable(struct rtwn_softc * sc)64 r21au_dfs_radar_disable(struct rtwn_softc *sc)
65 {
66 rtwn_bb_setbits(sc, 0x924, 0x00008000, 0);
67 }
68
69 static int
r21au_dfs_radar_is_enabled(struct rtwn_softc * sc)70 r21au_dfs_radar_is_enabled(struct rtwn_softc *sc)
71 {
72 return !!(rtwn_bb_read(sc, 0x924) & 0x00008000);
73 }
74
75 static int
r21au_dfs_radar_reset(struct rtwn_softc * sc)76 r21au_dfs_radar_reset(struct rtwn_softc *sc)
77 {
78 int error;
79
80 error = rtwn_bb_setbits(sc, 0x924, 0x00008000, 0);
81 if (error != 0)
82 return (error);
83
84 return (rtwn_bb_setbits(sc, 0x924, 0, 0x00008000));
85 }
86
87 static int
r21au_dfs_radar_enable(struct rtwn_softc * sc)88 r21au_dfs_radar_enable(struct rtwn_softc *sc)
89 {
90 #define RTWN_CHK(res) do { \
91 if (res != 0) \
92 return (EIO); \
93 } while(0)
94
95 RTWN_ASSERT_LOCKED(sc);
96
97 RTWN_CHK(rtwn_bb_setbits(sc, 0x814, 0x3fffffff, 0x04cc4d10));
98 RTWN_CHK(rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0xff, 0x06));
99 RTWN_CHK(rtwn_bb_write(sc, 0x918, 0x1c16ecdf));
100 RTWN_CHK(rtwn_bb_write(sc, 0x924, 0x0152a400));
101 RTWN_CHK(rtwn_bb_write(sc, 0x91c, 0x0fa21a20));
102 RTWN_CHK(rtwn_bb_write(sc, 0x920, 0xe0f57204));
103
104 return (r21au_dfs_radar_reset(sc));
105
106 #undef RTWN_CHK
107 }
108
109 static int
r21au_dfs_radar_is_detected(struct rtwn_softc * sc)110 r21au_dfs_radar_is_detected(struct rtwn_softc *sc)
111 {
112 return !!(rtwn_bb_read(sc, 0xf98) & 0x00020000);
113 }
114
115 void
r21au_chan_check(void * arg,int npending __unused)116 r21au_chan_check(void *arg, int npending __unused)
117 {
118 struct rtwn_softc *sc = arg;
119 struct r12a_softc *rs = sc->sc_priv;
120 struct ieee80211com *ic = &sc->sc_ic;
121
122 RTWN_LOCK(sc);
123 #ifdef DIAGNOSTIC
124 RTWN_DPRINTF(sc, RTWN_DEBUG_STATE,
125 "%s: periodical radar detection task\n", __func__);
126 #endif
127
128 if (!r21au_dfs_radar_is_enabled(sc)) {
129 if (rs->rs_flags & R12A_RADAR_ENABLED) {
130 /* should not happen */
131 device_printf(sc->sc_dev,
132 "%s: radar detection was turned off "
133 "unexpectedly, resetting...\n", __func__);
134
135 /* XXX something more appropriate? */
136 ieee80211_restart_all(ic);
137 }
138 RTWN_UNLOCK(sc);
139 return;
140 }
141
142 if (r21au_dfs_radar_is_detected(sc)) {
143 r21au_dfs_radar_reset(sc);
144
145 RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR, "%s: got radar event\n",
146 __func__);
147
148 RTWN_UNLOCK(sc);
149 IEEE80211_LOCK(ic);
150
151 ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
152
153 IEEE80211_UNLOCK(ic);
154 RTWN_LOCK(sc);
155 }
156
157 if (rs->rs_flags & R12A_RADAR_ENABLED) {
158 taskqueue_enqueue_timeout(taskqueue_thread,
159 &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
160 }
161 RTWN_UNLOCK(sc);
162 }
163
164 int
r21au_newstate(struct ieee80211vap * vap,enum ieee80211_state nstate,int arg)165 r21au_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
166 {
167 struct ieee80211com *ic = vap->iv_ic;
168 struct rtwn_softc *sc = ic->ic_softc;
169 struct rtwn_vap *rvp = RTWN_VAP(vap);
170 struct r12a_softc *rs = sc->sc_priv;
171 int error;
172
173 KASSERT(rvp->id == 0 || rvp->id == 1,
174 ("%s: unexpected vap id %d\n", __func__, rvp->id));
175
176 IEEE80211_UNLOCK(ic);
177 RTWN_LOCK(sc);
178
179 error = 0;
180 if (nstate == IEEE80211_S_CAC &&
181 !(rs->rs_flags & R12A_RADAR_ENABLED)) {
182 error = r21au_dfs_radar_enable(sc);
183 if (error != 0) {
184 device_printf(sc->sc_dev,
185 "%s: cannot enable radar detection\n", __func__);
186 goto fail;
187 }
188 rs->rs_flags |= R12A_RADAR_ENABLED;
189
190 RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
191 "%s: radar detection was enabled\n", __func__);
192
193 taskqueue_enqueue_timeout(taskqueue_thread,
194 &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
195 }
196
197 if ((nstate < IEEE80211_S_CAC || nstate == IEEE80211_S_CSA) &&
198 (rs->rs_flags & R12A_RADAR_ENABLED) &&
199 (sc->vaps[!rvp->id] == NULL ||
200 sc->vaps[!rvp->id]->vap.iv_state < IEEE80211_S_CAC ||
201 sc->vaps[!rvp->id]->vap.iv_state == IEEE80211_S_CSA)) {
202 taskqueue_cancel_timeout(taskqueue_thread, &rs->rs_chan_check,
203 NULL);
204
205 rs->rs_flags &= ~R12A_RADAR_ENABLED;
206 r21au_dfs_radar_disable(sc);
207
208 RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
209 "%s: radar detection was disabled\n", __func__);
210 }
211
212 fail:
213 RTWN_UNLOCK(sc);
214 IEEE80211_LOCK(ic);
215
216 if (error != 0)
217 return (error);
218
219 return (rs->rs_newstate[rvp->id](vap, nstate, arg));
220 }
221
222 void
r21au_scan_start(struct ieee80211com * ic)223 r21au_scan_start(struct ieee80211com *ic)
224 {
225 struct rtwn_softc *sc = ic->ic_softc;
226 struct r12a_softc *rs = sc->sc_priv;
227
228 RTWN_LOCK(sc);
229 if (rs->rs_flags & R12A_RADAR_ENABLED) {
230 RTWN_UNLOCK(sc);
231 while (taskqueue_cancel_timeout(taskqueue_thread,
232 &rs->rs_chan_check, NULL) != 0) {
233 taskqueue_drain_timeout(taskqueue_thread,
234 &rs->rs_chan_check);
235 }
236 RTWN_LOCK(sc);
237
238 r21au_dfs_radar_disable(sc);
239 RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
240 "%s: radar detection was (temporarily) disabled\n",
241 __func__);
242 }
243 RTWN_UNLOCK(sc);
244
245 rs->rs_scan_start(ic);
246 }
247
248 void
r21au_scan_end(struct ieee80211com * ic)249 r21au_scan_end(struct ieee80211com *ic)
250 {
251 struct rtwn_softc *sc = ic->ic_softc;
252 struct r12a_softc *rs = sc->sc_priv;
253 int error;
254
255 RTWN_LOCK(sc);
256 if (rs->rs_flags & R12A_RADAR_ENABLED) {
257 error = r21au_dfs_radar_enable(sc);
258 if (error != 0) {
259 device_printf(sc->sc_dev,
260 "%s: cannot re-enable radar detection\n",
261 __func__);
262
263 /* XXX */
264 ieee80211_restart_all(ic);
265 RTWN_UNLOCK(sc);
266 return;
267 }
268 RTWN_DPRINTF(sc, RTWN_DEBUG_RADAR,
269 "%s: radar detection was re-enabled\n", __func__);
270
271 taskqueue_enqueue_timeout(taskqueue_thread,
272 &rs->rs_chan_check, R21AU_RADAR_CHECK_PERIOD);
273 }
274 RTWN_UNLOCK(sc);
275
276 rs->rs_scan_end(ic);
277 }
278