blob: 23d27c4a1b0b0535ff1769dd8c797f9be85649dd [file] [log] [blame]
/*
* Copyright (c) 2002-2013 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(u_int32_t sample_pri, u_int32_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(u_int32_t highestpri , u_int32_t midpri,
u_int32_t lowestpri , u_int32_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,
u_int32_t deltaT, u_int32_t width)
{
u_int32_t refpri, refdur, searchpri=0, deltapri;//, averagerefpri;
u_int32_t n, i, primargin, durmargin;
int score[DFS_MAX_DL_SIZE], delayindex, dindex, found=0;
struct dfs_delayline *dl;
u_int32_t scoreindex, lowpriindex= 0, lowpri = 0xffff;
#if 0
int numpulses=0;
#endif
int higherthan, lowerthan, numscores;
int numpulseshigh=0, numpulsesmid=0, numpulsestemp=0;
u_int32_t lowestscore=0, lowestscoreindex=0, lowestpri=0;
u_int32_t midscore=0, midscoreindex=0, midpri=0;
u_int32_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 */