blob: 8cf4a2c8cd4a2ad11e0367da7caf0127bb8c1ae5 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/*===========================================================================
29
30 dfs_misc.c
31
32 OVERVIEW:
33
34 Source code borrowed from QCA_MAIN DFS module
35
36 DEPENDENCIES:
37
38 Are listed for each API below.
39
40 ===========================================================================*/
41
42/*===========================================================================
43
44 EDIT HISTORY FOR FILE
45
46 This section contains comments describing changes made to the module.
47 Notice that changes are listed in reverse chronological order.
48
49 when who what, where, why
50 ---------- --- --------------------------------------------------------
51
52 ===========================================================================*/
53
54#include "dfs.h"
55/* TO DO DFS
56 #include <ieee80211_var.h>
57 */
58#ifndef UNINET
59/* TO DO DFS
60 #include <ieee80211_channel.h>
61 */
62#endif
63#ifdef ATH_SUPPORT_DFS
64
65static int adjust_pri_per_chan_busy(int ext_chan_busy, int pri_margin)
66{
67 int adjust_pri = 0;
68
69 if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) {
70
71 adjust_pri =
72 (ext_chan_busy -
73 DFS_EXT_CHAN_LOADING_THRESH) * (pri_margin);
74 adjust_pri /= 100;
75
76 }
77 return adjust_pri;
78}
79
80static int adjust_thresh_per_chan_busy(int ext_chan_busy, int thresh)
81{
82 int adjust_thresh = 0;
83
84 if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) {
85
86 adjust_thresh =
87 (ext_chan_busy - DFS_EXT_CHAN_LOADING_THRESH) * thresh;
88 adjust_thresh /= 100;
89
90 }
91 return adjust_thresh;
92}
93
94/* For the extension channel, if legacy traffic is present, we see a lot of false alarms,
95 so make the PRI margin narrower depending on the busy % for the extension channel.*/
96
97int
98dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect,
99 int is_fixed_pattern)
100{
101
102 int adjust_pri = 0, ext_chan_busy = 0;
103 int pri_margin;
104
105 if (is_fixed_pattern)
106 pri_margin = DFS_DEFAULT_FIXEDPATTERN_PRI_MARGIN;
107 else
108 pri_margin = DFS_DEFAULT_PRI_MARGIN;
109
110 if (IS_CHAN_HT40(dfs->ic->ic_curchan)) {
111 ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic);
112 if (ext_chan_busy >= 0) {
113 dfs->dfs_rinfo.ext_chan_busy_ts =
114 dfs->ic->ic_get_TSF64(dfs->ic);
115 dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy;
116 } else {
117 /* Check to see if the cached value of ext_chan_busy can be used */
118 ext_chan_busy = 0;
119 if (dfs->dfs_rinfo.dfs_ext_chan_busy) {
120 if (dfs->dfs_rinfo.rn_lastfull_ts <
121 dfs->dfs_rinfo.ext_chan_busy_ts) {
122 ext_chan_busy =
123 dfs->dfs_rinfo.dfs_ext_chan_busy;
124 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
125 " PRI Use cached copy of ext_chan_busy extchanbusy=%d \n",
126 ext_chan_busy);
127 }
128 }
129 }
130 adjust_pri =
131 adjust_pri_per_chan_busy(ext_chan_busy, pri_margin);
132
133 pri_margin -= adjust_pri;
134 }
135 return pri_margin;
136}
137
138/* For the extension channel, if legacy traffic is present, we see a lot of false alarms,
139 so make the thresholds higher depending on the busy % for the extension channel.*/
140
141int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf,
142 int is_extchan_detect)
143{
144 int ext_chan_busy = 0;
145 int thresh, adjust_thresh = 0;
146
147 thresh = rf->rf_threshold;
148
149 if (IS_CHAN_HT40(dfs->ic->ic_curchan)) {
150 ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic);
151 if (ext_chan_busy >= 0) {
152 dfs->dfs_rinfo.ext_chan_busy_ts =
153 dfs->ic->ic_get_TSF64(dfs->ic);
154 dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy;
155 } else {
156 /* Check to see if the cached value of ext_chan_busy can be used */
157 ext_chan_busy = 0;
158 if (dfs->dfs_rinfo.dfs_ext_chan_busy) {
159 if (dfs->dfs_rinfo.rn_lastfull_ts <
160 dfs->dfs_rinfo.ext_chan_busy_ts) {
161 ext_chan_busy =
162 dfs->dfs_rinfo.dfs_ext_chan_busy;
163 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
164 " THRESH Use cached copy of ext_chan_busy extchanbusy=%d rn_lastfull_ts=%llu ext_chan_busy_ts=%llu\n",
165 ext_chan_busy,
166 (unsigned long long)dfs->
167 dfs_rinfo.rn_lastfull_ts,
168 (unsigned long long)dfs->
169 dfs_rinfo.ext_chan_busy_ts);
170 }
171 }
172 }
173
174 adjust_thresh =
175 adjust_thresh_per_chan_busy(ext_chan_busy, thresh);
176
177 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
178 " filterID=%d extchanbusy=%d adjust_thresh=%d\n",
179 rf->rf_pulseid, ext_chan_busy, adjust_thresh);
180
181 thresh += adjust_thresh;
182 }
183 return thresh;
184}
185
186uint32_t dfs_round(int32_t val)
187{
188 uint32_t ival, rem;
189
190 if (val < 0)
191 return 0;
192 ival = val / 100;
193 rem = val - (ival * 100);
194 if (rem < 50)
195 return ival;
196 else
197 return (ival + 1);
198}
199
200struct ieee80211_channel *ieee80211_get_extchan(struct ieee80211com *ic)
201{
202 int chan_offset = 0;
203 if (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(ic->ic_curchan)) {
204 chan_offset = 20;
205 } else if (IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(ic->ic_curchan)) {
206 chan_offset = -20;
207 } else {
208 return NULL;
209 }
210 return (ic->
211 ic_find_channel(ic, ic->ic_curchan->ic_freq + chan_offset,
212 IEEE80211_CHAN_11NA_HT20));
213}
214
215/*
216 * Finds the radar state entry that matches the current channel
217 */
218struct dfs_state *dfs_getchanstate(struct ath_dfs *dfs, uint8_t *index,
219 int ext_chan_flag)
220{
221 struct dfs_state *rs = NULL;
222 int i;
223 struct ieee80211_channel *cmp_ch;
224
225 if (dfs == NULL) {
226 printk("%s[%d]: sc_dfs is NULL\n", __func__, __LINE__);
227 /* DFS_DPRINTK(dfs, ATH_DEBUG_DFS,"%s: sc_dfs is NULL\n",__func__); */
228 return NULL;
229 }
230
231 if (ext_chan_flag) {
232 cmp_ch = ieee80211_get_extchan(dfs->ic);
233 if (cmp_ch) {
234 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
235 "Extension channel freq = %u flags=0x%x\n",
236 cmp_ch->ic_freq, cmp_ch->ic_flagext);
237 } else {
238 return NULL;
239 }
240
241 } else {
242 cmp_ch = dfs->ic->ic_curchan;
243 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
244 "Primary channel freq = %u flags=0x%x\n",
245 cmp_ch->ic_freq, cmp_ch->ic_flagext);
246 }
247 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) {
248 if ((dfs->dfs_radar[i].rs_chan.ic_freq == cmp_ch->ic_freq) &&
249 (dfs->dfs_radar[i].rs_chan.ic_flags == cmp_ch->ic_flags)) {
250 if (index != NULL)
251 *index = (uint8_t) i;
252 return &(dfs->dfs_radar[i]);
253 }
254 }
255 /* No existing channel found, look for first free channel state entry */
256 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) {
257 if (dfs->dfs_radar[i].rs_chan.ic_freq == 0) {
258 rs = &(dfs->dfs_radar[i]);
259 /* Found one, set channel info and default thresholds */
260 rs->rs_chan = *cmp_ch;
261
262 /* Copy the parameters from the default set */
263 ath_dfs_phyerr_param_copy(&rs->rs_param,
264 &dfs->dfs_defaultparams);
265
266 if (index != NULL)
267 *index = (uint8_t) i;
268 return (rs);
269 }
270 }
271 DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s: No more radar states left.\n",
272 __func__);
273 return (NULL);
274}
275
276#endif /* ATH_SUPPORT_DFS */