blob: 71c04b573b0a3eeb0fa8a4a1d5dc366931671ec0 [file] [log] [blame]
/*
* Copyright (c) 2002-2014 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/*===========================================================================
dfs_staggered.c
OVERVIEW:
Source code borrowed from QCA_MAIN DFS module
DEPENDENCIES:
Are listed for each API below.
===========================================================================*/
/*===========================================================================
EDIT HISTORY FOR FILE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
when who what, where, why
---------- --- --------------------------------------------------------
===========================================================================*/
#include "dfs.h"
/* TO DO DFS
#include <ieee80211_var.h>
*/
#ifdef ATH_SUPPORT_DFS
static int is_pri_multiple(uint32_t sample_pri, uint32_t refpri)
{
#define MAX_ALLOWED_MISSED 3
int i;
if (sample_pri < refpri || (!refpri))
return 0;
for (i = 1; i <= MAX_ALLOWED_MISSED; i++) {
if ((sample_pri % (i * refpri) <= 5)) {
/* printk("sample_pri=%d is a multiple of refpri=%d\n", sample_pri, refpri); */
return 1;
}
}
return 0;
#undef MAX_ALLOWED_MISSED
}
static int is_unique_pri(uint32_t highestpri, uint32_t midpri,
uint32_t lowestpri, uint32_t refpri)
{
#define DFS_STAGGERED_PRI_MARGIN_MIN 20
#define DFS_STAGGERED_PRI_MARGIN_MAX 400
if ((DFS_DIFF(lowestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) &&
(DFS_DIFF(midpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) &&
(DFS_DIFF(highestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN)) {
return 1;
} else {
if ((is_pri_multiple(refpri, highestpri))
|| (is_pri_multiple(refpri, lowestpri))
|| (is_pri_multiple(refpri, midpri)))
return 0;
}
return 0;
#undef DFS_STAGGERED_PRI_MARGIN_MIN
#undef DFS_STAGGERED_PRI_MARGIN_MAX
}
int dfs_staggered_check(struct ath_dfs *dfs, struct dfs_filter *rf,
uint32_t deltaT, uint32_t width)
{
uint32_t refpri, refdur, searchpri = 0, deltapri; /* , averagerefpri; */
uint32_t n, i, primargin, durmargin;
int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0;
struct dfs_delayline *dl;
uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff;
#if 0
int numpulses = 0;
#endif
int higherthan, lowerthan, numscores;
int numpulseshigh = 0, numpulsesmid = 0, numpulsestemp = 0;
uint32_t lowestscore = 0, lowestscoreindex = 0, lowestpri = 0;
uint32_t midscore = 0, midscoreindex = 0, midpri = 0;
uint32_t highestscore = 0, highestscoreindex = 0, highestpri = 0;
dl = &rf->rf_dl;
if (dl->dl_numelems < (rf->rf_threshold - 1)) {
DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
"numelems %d < threshold for filter %d\n",
dl->dl_numelems, rf->rf_pulseid);
return 0;
}
if (deltaT > rf->rf_filterlen) {
DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
"numelems %d < threshold for filter %d\n",
dl->dl_numelems, rf->rf_pulseid);
return 0;
}
primargin = 6;
if (rf->rf_maxdur < 10) {
durmargin = 4;
} else {
durmargin = 6;
}
OS_MEMZERO(score, sizeof(int) * DFS_MAX_DL_SIZE);
/* find out the lowest pri */
for (n = 0; n < dl->dl_numelems; n++) {
delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
refpri = dl->dl_elems[delayindex].de_time;
if (refpri == 0)
continue;
else if (refpri < lowpri) {
lowpri = dl->dl_elems[delayindex].de_time;
lowpriindex = n;
}
}
/* find out the each delay element's pri score */
for (n = 0; n < dl->dl_numelems; n++) {
delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
refpri = dl->dl_elems[delayindex].de_time;
if (refpri == 0) {
continue;
}
if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) {
score[n] = 0;
continue;
}
for (i = 0; i < dl->dl_numelems; i++) {
dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
searchpri = dl->dl_elems[dindex].de_time;
deltapri = DFS_DIFF(searchpri, refpri);
if (deltapri < primargin)
score[n]++;
}
}
for (n = 0; n < dl->dl_numelems; n++) {
delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
refdur = dl->dl_elems[delayindex].de_time;
DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "score[%d]=%d pri=%d\n", n,
score[n], refdur);
}
/* find out the 2 or 3 highest scorers */
scoreindex = 0;
highestscore = 0;
highestscoreindex = 0;
highestpri = 0;
numscores = 0;
lowestscore = 0;
for (n = 0; n < dl->dl_numelems; n++) {
higherthan = 0;
lowerthan = 0;
delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
refpri = dl->dl_elems[delayindex].de_time;
if ((score[n] >= highestscore) &&
(is_unique_pri(highestpri, midpri, lowestpri, refpri))) {
lowestscore = midscore;
lowestpri = midpri;
lowestscoreindex = midscoreindex;
midscore = highestscore;
midpri = highestpri;
midscoreindex = highestscoreindex;
highestscore = score[n];
highestpri = refpri;
highestscoreindex = n;
} else {
if ((score[n] >= midscore) &&
(is_unique_pri
(highestpri, midpri, lowestpri, refpri))) {
lowestscore = midscore;
lowestpri = midpri;
lowestscoreindex = midscoreindex;
midscore = score[n];
midpri = refpri;
midscoreindex = n;
} else if ((score[n] >= lowestscore) &&
(is_unique_pri
(highestpri, midpri, lowestpri, refpri))) {
lowestscore = score[n];
lowestpri = refpri;
lowestscoreindex = n;
}
}
}
if (midscore == 0) {
/* This means we have only 1 pulse type. It can not be staggered! */
return 0;
}
DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
"FINAL highestscore=%d highestscoreindex=%d highestpri=%d\n",
highestscore, highestscoreindex, highestpri);
DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
"FINAL lowestscore=%d lowestscoreindex=%d lowpri=%d\n",
lowestscore, lowestscoreindex, lowestpri);
DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
"FINAL midscore=%d midscoreindex=%d midpri=%d\n",
midscore, midscoreindex, midpri);
delayindex = (dl->dl_firstelem + highestscoreindex) & DFS_MAX_DL_MASK;
refdur = dl->dl_elems[delayindex].de_dur;
refpri = dl->dl_elems[delayindex].de_time;
DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
"highscoreindex=%d refdur=%d refpri=%d\n",
highestscoreindex, refdur, refpri);
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0,
highestpri);
numpulseshigh = numpulsestemp;
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0,
highestpri + midpri);
if (numpulsestemp > numpulseshigh) {
numpulseshigh = numpulsestemp;
}
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0,
highestpri + midpri + lowestpri);
if (numpulsestemp > numpulseshigh) {
numpulseshigh = numpulsestemp;
}
delayindex = (dl->dl_firstelem + midscoreindex) & DFS_MAX_DL_MASK;
refdur = dl->dl_elems[delayindex].de_dur;
refpri = dl->dl_elems[delayindex].de_time;
DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
"midscoreindex=%d refdur=%d refpri=%d\n",
midscoreindex, refdur, refpri);
/* numpulsesmid = dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur,0, 1); */
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, midpri);
numpulsesmid = numpulsestemp;
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0,
highestpri + midpri);
if (numpulsestemp > numpulsesmid) {
numpulsesmid = numpulsestemp;
}
numpulsestemp =
dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0,
highestpri + midpri + lowestpri);
if (numpulsestemp > numpulsesmid) {
numpulsesmid = numpulsestemp;
}
/*delayindex = (dl->dl_firstelem + lowestscoreindex) & DFS_MAX_DL_MASK;
refdur = dl->dl_elems[delayindex].de_dur;
refpri = dl->dl_elems[delayindex].de_time;
DFS_DPRINTK(ic, ATH_DEBUG_DFS1, "lowestscoreindex=%d refdur=%d refpri=%d\n", lowestscoreindex, refdur, refpri);
numpulseslow = dfs_bin_pri_check(dfs, rf, dl, lowestscore, refpri, refdur,0, 1);
*/
DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
"numpulseshigh=%d, numpulsesmid=%d\n",
numpulseshigh, numpulsesmid);
/* printf("numpulseshigh=%d, numpulsesmid=%d, numpulseslow %d\n",numpulseshigh, numpulsesmid, numpulseslow); */
if ((numpulseshigh >= rf->rf_threshold)
&& (numpulsesmid >= rf->rf_threshold)) {
/*if (numpulses >= rf->rf_threshold) { */
found = 1;
DFS_DPRINTK(dfs, ATH_DEBUG_DFS2,
"MATCH filter=%u numpulseshigh=%u numpulsesmid= %u thresh=%u\n",
rf->rf_pulseid, numpulseshigh, numpulsesmid,
rf->rf_threshold);
}
return found;
}
#endif /* ATH_SUPPORT_DFS */