148237774SAdrian Chadd /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
448237774SAdrian Chadd * Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd
548237774SAdrian Chadd * All rights reserved.
648237774SAdrian Chadd *
748237774SAdrian Chadd * Redistribution and use in source and binary forms, with or without
848237774SAdrian Chadd * modification, are permitted provided that the following conditions
948237774SAdrian Chadd * are met:
1048237774SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
1148237774SAdrian Chadd * notice, this list of conditions and the following disclaimer,
1248237774SAdrian Chadd * without modification.
1348237774SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1448237774SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1548237774SAdrian Chadd * redistribution must be conditioned upon including a substantially
1648237774SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
1748237774SAdrian Chadd *
1848237774SAdrian Chadd * NO WARRANTY
1948237774SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2048237774SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2148237774SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2248237774SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2348237774SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2448237774SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2548237774SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2648237774SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2748237774SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2848237774SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2948237774SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
3048237774SAdrian Chadd */
3148237774SAdrian Chadd #include <sys/cdefs.h>
3248237774SAdrian Chadd /*
3348237774SAdrian Chadd * This implements an empty DFS module.
3448237774SAdrian Chadd */
35c312fb4aSAdrian Chadd #include "opt_ath.h"
3648237774SAdrian Chadd #include "opt_inet.h"
3748237774SAdrian Chadd #include "opt_wlan.h"
3848237774SAdrian Chadd
3948237774SAdrian Chadd #include <sys/param.h>
4048237774SAdrian Chadd #include <sys/systm.h>
4148237774SAdrian Chadd #include <sys/sysctl.h>
4248237774SAdrian Chadd #include <sys/kernel.h>
4348237774SAdrian Chadd #include <sys/lock.h>
4476039bc8SGleb Smirnoff #include <sys/malloc.h>
4548237774SAdrian Chadd #include <sys/mutex.h>
4648237774SAdrian Chadd #include <sys/errno.h>
4748237774SAdrian Chadd
4848237774SAdrian Chadd #include <machine/bus.h>
4948237774SAdrian Chadd #include <machine/resource.h>
5048237774SAdrian Chadd #include <sys/bus.h>
5148237774SAdrian Chadd
5248237774SAdrian Chadd #include <sys/socket.h>
5348237774SAdrian Chadd
5448237774SAdrian Chadd #include <net/if.h>
5576039bc8SGleb Smirnoff #include <net/if_var.h>
5648237774SAdrian Chadd #include <net/if_media.h>
5748237774SAdrian Chadd #include <net/if_arp.h>
5848237774SAdrian Chadd #include <net/ethernet.h> /* XXX for ether_sprintf */
5948237774SAdrian Chadd
6048237774SAdrian Chadd #include <net80211/ieee80211_var.h>
6148237774SAdrian Chadd
6248237774SAdrian Chadd #include <net/bpf.h>
6348237774SAdrian Chadd
6448237774SAdrian Chadd #ifdef INET
6548237774SAdrian Chadd #include <netinet/in.h>
6648237774SAdrian Chadd #include <netinet/if_ether.h>
6748237774SAdrian Chadd #endif
6848237774SAdrian Chadd
6948237774SAdrian Chadd #include <dev/ath/if_athvar.h>
7048237774SAdrian Chadd #include <dev/ath/if_athdfs.h>
7148237774SAdrian Chadd
7248237774SAdrian Chadd #include <dev/ath/ath_hal/ah_desc.h>
7348237774SAdrian Chadd
7448237774SAdrian Chadd /*
7548237774SAdrian Chadd * Methods which are required
7648237774SAdrian Chadd */
7748237774SAdrian Chadd
7848237774SAdrian Chadd /*
7948237774SAdrian Chadd * Attach DFS to the given interface
8048237774SAdrian Chadd */
8148237774SAdrian Chadd int
ath_dfs_attach(struct ath_softc * sc)8248237774SAdrian Chadd ath_dfs_attach(struct ath_softc *sc)
8348237774SAdrian Chadd {
84d77363adSAdrian Chadd return (1);
8548237774SAdrian Chadd }
8648237774SAdrian Chadd
8748237774SAdrian Chadd /*
8848237774SAdrian Chadd * Detach DFS from the given interface
8948237774SAdrian Chadd */
9048237774SAdrian Chadd int
ath_dfs_detach(struct ath_softc * sc)9148237774SAdrian Chadd ath_dfs_detach(struct ath_softc *sc)
9248237774SAdrian Chadd {
93d77363adSAdrian Chadd return (1);
9448237774SAdrian Chadd }
9548237774SAdrian Chadd
9648237774SAdrian Chadd /*
97d77363adSAdrian Chadd * Enable radar check. Return 1 if the driver should
98d77363adSAdrian Chadd * enable radar PHY errors, or 0 if not.
9948237774SAdrian Chadd */
100bfa5e927SAdrian Chadd int
ath_dfs_radar_enable(struct ath_softc * sc,struct ieee80211_channel * chan)10148237774SAdrian Chadd ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan)
10248237774SAdrian Chadd {
10341059135SAdrian Chadd #if 1
104ab434358SAdrian Chadd HAL_PHYERR_PARAM pe;
105ab434358SAdrian Chadd
106b7005313SAdrian Chadd /* Check if the hardware supports radar reporting */
107b7005313SAdrian Chadd /* XXX TODO: migrate HAL_CAP_RADAR/HAL_CAP_AR to somewhere public! */
108b7005313SAdrian Chadd if (ath_hal_getcapability(sc->sc_ah,
109b7005313SAdrian Chadd HAL_CAP_PHYDIAG, 0, NULL) != HAL_OK)
110b7005313SAdrian Chadd return (0);
111b7005313SAdrian Chadd
11248237774SAdrian Chadd /* Check if the current channel is radar-enabled */
11348237774SAdrian Chadd if (! IEEE80211_IS_CHAN_DFS(chan))
114bfa5e927SAdrian Chadd return (0);
115bfa5e927SAdrian Chadd
116b7005313SAdrian Chadd /* Fetch the default parameters */
117b7005313SAdrian Chadd memset(&pe, '\0', sizeof(pe));
118b7005313SAdrian Chadd if (! ath_hal_getdfsdefaultthresh(sc->sc_ah, &pe))
119b7005313SAdrian Chadd return (0);
120b7005313SAdrian Chadd
121ab434358SAdrian Chadd /* Enable radar PHY error reporting */
122ab434358SAdrian Chadd sc->sc_dodfs = 1;
123ab434358SAdrian Chadd
124b7005313SAdrian Chadd /* Tell the hardware to enable radar reporting */
125ab434358SAdrian Chadd pe.pe_enabled = 1;
126ab434358SAdrian Chadd
127ab434358SAdrian Chadd /* Flip on extension channel events only if doing HT40 */
128ab434358SAdrian Chadd if (IEEE80211_IS_CHAN_HT40(chan))
129ab434358SAdrian Chadd pe.pe_extchannel = 1;
130ab434358SAdrian Chadd else
131ab434358SAdrian Chadd pe.pe_extchannel = 0;
132ab434358SAdrian Chadd
133ab434358SAdrian Chadd ath_hal_enabledfs(sc->sc_ah, &pe);
134bfa5e927SAdrian Chadd
135be7f7a95SAdrian Chadd /*
136be7f7a95SAdrian Chadd * Disable strong signal fast diversity - needed for
137be7f7a95SAdrian Chadd * AR5212 and similar PHYs for reliable short pulse
138be7f7a95SAdrian Chadd * duration.
139be7f7a95SAdrian Chadd */
140be7f7a95SAdrian Chadd (void) ath_hal_setcapability(sc->sc_ah, HAL_CAP_DIVERSITY, 2, 0, NULL);
141be7f7a95SAdrian Chadd
142bfa5e927SAdrian Chadd return (1);
143ab434358SAdrian Chadd #else
144ab434358SAdrian Chadd return (0);
145ab434358SAdrian Chadd #endif
14648237774SAdrian Chadd }
14748237774SAdrian Chadd
14848237774SAdrian Chadd /*
149c9b690d3SAdrian Chadd * Explicity disable radar reporting.
150c9b690d3SAdrian Chadd *
151c9b690d3SAdrian Chadd * Return 0 if it was disabled, < 0 on error.
152c9b690d3SAdrian Chadd */
153c9b690d3SAdrian Chadd int
ath_dfs_radar_disable(struct ath_softc * sc)154c9b690d3SAdrian Chadd ath_dfs_radar_disable(struct ath_softc *sc)
155c9b690d3SAdrian Chadd {
15641059135SAdrian Chadd #if 1
157c9b690d3SAdrian Chadd HAL_PHYERR_PARAM pe;
158c9b690d3SAdrian Chadd
159c9b690d3SAdrian Chadd (void) ath_hal_getdfsthresh(sc->sc_ah, &pe);
160c9b690d3SAdrian Chadd pe.pe_enabled = 0;
161c9b690d3SAdrian Chadd (void) ath_hal_enabledfs(sc->sc_ah, &pe);
162c9b690d3SAdrian Chadd return (0);
163c9b690d3SAdrian Chadd #else
164c9b690d3SAdrian Chadd return (0);
165c9b690d3SAdrian Chadd #endif
166c9b690d3SAdrian Chadd }
167c9b690d3SAdrian Chadd
168c9b690d3SAdrian Chadd /*
16948237774SAdrian Chadd * Process DFS related PHY errors
170d77363adSAdrian Chadd *
171d77363adSAdrian Chadd * The mbuf is not "ours" and if we want a copy, we have
172d77363adSAdrian Chadd * to take a copy. It'll be freed after this function returns.
17348237774SAdrian Chadd */
17448237774SAdrian Chadd void
ath_dfs_process_phy_err(struct ath_softc * sc,struct mbuf * m,uint64_t tsf,struct ath_rx_status * rxstat)175d77363adSAdrian Chadd ath_dfs_process_phy_err(struct ath_softc *sc, struct mbuf *m,
17648237774SAdrian Chadd uint64_t tsf, struct ath_rx_status *rxstat)
17748237774SAdrian Chadd {
17848237774SAdrian Chadd
17948237774SAdrian Chadd }
18048237774SAdrian Chadd
18148237774SAdrian Chadd /*
182f6b6084bSPedro F. Giffuni * Process the radar events and determine whether a DFS event has occurred.
18348237774SAdrian Chadd *
18448237774SAdrian Chadd * This is designed to run outside of the RX processing path.
18548237774SAdrian Chadd * The RX path will call ath_dfs_tasklet_needed() to see whether
18648237774SAdrian Chadd * the task/callback running this routine needs to be called.
18748237774SAdrian Chadd */
18848237774SAdrian Chadd int
ath_dfs_process_radar_event(struct ath_softc * sc,struct ieee80211_channel * chan)18948237774SAdrian Chadd ath_dfs_process_radar_event(struct ath_softc *sc,
19048237774SAdrian Chadd struct ieee80211_channel *chan)
19148237774SAdrian Chadd {
192d77363adSAdrian Chadd return (0);
19348237774SAdrian Chadd }
19448237774SAdrian Chadd
19548237774SAdrian Chadd /*
19636daf049SEitan Adler * Determine whether the DFS check task needs to be queued.
19748237774SAdrian Chadd *
19848237774SAdrian Chadd * This is called in the RX task when the current batch of packets
19948237774SAdrian Chadd * have been received. It will return whether there are any radar
20048237774SAdrian Chadd * events for ath_dfs_process_radar_event() to handle.
20148237774SAdrian Chadd */
20248237774SAdrian Chadd int
ath_dfs_tasklet_needed(struct ath_softc * sc,struct ieee80211_channel * chan)20348237774SAdrian Chadd ath_dfs_tasklet_needed(struct ath_softc *sc, struct ieee80211_channel *chan)
20448237774SAdrian Chadd {
205d77363adSAdrian Chadd return (0);
20648237774SAdrian Chadd }
20748237774SAdrian Chadd
20848237774SAdrian Chadd /*
209c5f2a23cSAdrian Chadd * Handle ioctl requests from the diagnostic interface.
210c5f2a23cSAdrian Chadd *
211c5f2a23cSAdrian Chadd * The initial part of this code resembles ath_ioctl_diag();
212c5f2a23cSAdrian Chadd * it's likely a good idea to reduce duplication between
213c5f2a23cSAdrian Chadd * these two routines.
21448237774SAdrian Chadd */
21548237774SAdrian Chadd int
ath_ioctl_phyerr(struct ath_softc * sc,struct ath_diag * ad)21648237774SAdrian Chadd ath_ioctl_phyerr(struct ath_softc *sc, struct ath_diag *ad)
21748237774SAdrian Chadd {
218c5f2a23cSAdrian Chadd unsigned int id = ad->ad_id & ATH_DIAG_ID;
219c5f2a23cSAdrian Chadd void *indata = NULL;
220c5f2a23cSAdrian Chadd void *outdata = NULL;
221c5f2a23cSAdrian Chadd u_int32_t insize = ad->ad_in_size;
222c5f2a23cSAdrian Chadd u_int32_t outsize = ad->ad_out_size;
223c5f2a23cSAdrian Chadd int error = 0;
224c5f2a23cSAdrian Chadd HAL_PHYERR_PARAM peout;
225c5f2a23cSAdrian Chadd HAL_PHYERR_PARAM *pe;
226c5f2a23cSAdrian Chadd
227c5f2a23cSAdrian Chadd if (ad->ad_id & ATH_DIAG_IN) {
228c5f2a23cSAdrian Chadd /*
229c5f2a23cSAdrian Chadd * Copy in data.
230c5f2a23cSAdrian Chadd */
231c5f2a23cSAdrian Chadd indata = malloc(insize, M_TEMP, M_NOWAIT);
232c5f2a23cSAdrian Chadd if (indata == NULL) {
233c5f2a23cSAdrian Chadd error = ENOMEM;
234c5f2a23cSAdrian Chadd goto bad;
235c5f2a23cSAdrian Chadd }
236c5f2a23cSAdrian Chadd error = copyin(ad->ad_in_data, indata, insize);
237c5f2a23cSAdrian Chadd if (error)
238c5f2a23cSAdrian Chadd goto bad;
239c5f2a23cSAdrian Chadd }
240c5f2a23cSAdrian Chadd if (ad->ad_id & ATH_DIAG_DYN) {
241c5f2a23cSAdrian Chadd /*
242c5f2a23cSAdrian Chadd * Allocate a buffer for the results (otherwise the HAL
243c5f2a23cSAdrian Chadd * returns a pointer to a buffer where we can read the
244c5f2a23cSAdrian Chadd * results). Note that we depend on the HAL leaving this
245c5f2a23cSAdrian Chadd * pointer for us to use below in reclaiming the buffer;
246c5f2a23cSAdrian Chadd * may want to be more defensive.
247c5f2a23cSAdrian Chadd */
248c5f2a23cSAdrian Chadd outdata = malloc(outsize, M_TEMP, M_NOWAIT);
249c5f2a23cSAdrian Chadd if (outdata == NULL) {
250c5f2a23cSAdrian Chadd error = ENOMEM;
251c5f2a23cSAdrian Chadd goto bad;
252c5f2a23cSAdrian Chadd }
253c5f2a23cSAdrian Chadd }
254c5f2a23cSAdrian Chadd switch (id) {
255c5f2a23cSAdrian Chadd case DFS_SET_THRESH:
256c5f2a23cSAdrian Chadd if (insize < sizeof(HAL_PHYERR_PARAM)) {
25799271119SAdrian Chadd error = EINVAL;
258c5f2a23cSAdrian Chadd break;
259c5f2a23cSAdrian Chadd }
260c5f2a23cSAdrian Chadd pe = (HAL_PHYERR_PARAM *) indata;
261c5f2a23cSAdrian Chadd ath_hal_enabledfs(sc->sc_ah, pe);
262c5f2a23cSAdrian Chadd break;
263c5f2a23cSAdrian Chadd case DFS_GET_THRESH:
264c5f2a23cSAdrian Chadd memset(&peout, 0, sizeof(peout));
265c5f2a23cSAdrian Chadd outsize = sizeof(HAL_PHYERR_PARAM);
266c5f2a23cSAdrian Chadd ath_hal_getdfsthresh(sc->sc_ah, &peout);
267c5f2a23cSAdrian Chadd pe = (HAL_PHYERR_PARAM *) outdata;
268c5f2a23cSAdrian Chadd memcpy(pe, &peout, sizeof(*pe));
269c5f2a23cSAdrian Chadd break;
270c5f2a23cSAdrian Chadd default:
27199271119SAdrian Chadd error = EINVAL;
272c5f2a23cSAdrian Chadd }
273c5f2a23cSAdrian Chadd if (outsize < ad->ad_out_size)
274c5f2a23cSAdrian Chadd ad->ad_out_size = outsize;
275c5f2a23cSAdrian Chadd if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
27699271119SAdrian Chadd error = EFAULT;
277c5f2a23cSAdrian Chadd bad:
278c5f2a23cSAdrian Chadd if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
279c5f2a23cSAdrian Chadd free(indata, M_TEMP);
280c5f2a23cSAdrian Chadd if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
281c5f2a23cSAdrian Chadd free(outdata, M_TEMP);
282d77363adSAdrian Chadd return (error);
28348237774SAdrian Chadd }
28448237774SAdrian Chadd
28548237774SAdrian Chadd /*
28648237774SAdrian Chadd * Get the current DFS thresholds from the HAL
28748237774SAdrian Chadd */
28848237774SAdrian Chadd int
ath_dfs_get_thresholds(struct ath_softc * sc,HAL_PHYERR_PARAM * param)28948237774SAdrian Chadd ath_dfs_get_thresholds(struct ath_softc *sc, HAL_PHYERR_PARAM *param)
29048237774SAdrian Chadd {
29148237774SAdrian Chadd ath_hal_getdfsthresh(sc->sc_ah, param);
292d77363adSAdrian Chadd return (1);
29348237774SAdrian Chadd }
294