| /* |
| * 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 */ |