static OS_TIMER_FUNC(dfs_testtimer_task) { struct ieee80211com *ic; struct ath_dfs *dfs = NULL; OS_GET_TIMER_ARG(ic, struct ieee80211com *); dfs = (struct ath_dfs *)ic->ic_dfs; /* XXX no locking? */ dfs->ath_dfstest = 0; /* * Flip the channel back to the original channel. * Make sure this is done properly with a CSA. */ DFS_PRINTK("%s: go back to channel %d\n", __func__, dfs->ath_dfstest_ieeechan); /* * XXX The mere existence of this method indirection * to a umac function means this code belongs in * the driver, _not_ here. Please fix this! */ ic->ic_start_csa(ic, dfs->ath_dfstest_ieeechan); }
/* * Mark a channel as having interference detected upon it. * * This adds the interference marker to both the primary and * extension channel. * * XXX TODO: make the NOL and channel interference logic a bit smarter * so only the channel with the radar event is marked, rather than * both the primary and extension. */ static void dfs_channel_mark_radar(struct ath_dfs *dfs, struct ieee80211_channel *chan) { struct ieee80211_channel_list chan_info; int i; //chan->ic_flagext |= CHANNEL_INTERFERENCE; /* * If radar is detected in 40MHz mode, add both the primary and the * extension channels to the NOL. chan is the channel data we return * to the ath_dev layer which passes it on to the 80211 layer. * As we want the AP to change channels and send out a CSA, * we always pass back the primary channel data to the ath_dev layer. */ if ((dfs->dfs_rinfo.rn_use_nol == 1) && (dfs->ic->ic_opmode == IEEE80211_M_HOSTAP || #if ATH_SUPPORT_DFS && ATH_SUPPORT_STA_DFS dfs->ic->ic_opmode == IEEE80211_M_IBSS || ((dfs->ic->ic_opmode == IEEE80211_M_STA) && (ieee80211com_has_cap_ext(dfs->ic,IEEE80211_CEXT_STADFS))))) { #else dfs->ic->ic_opmode == IEEE80211_M_IBSS)) { #endif chan_info.cl_nchans= 0; dfs->ic->ic_get_ext_chan_info (dfs->ic, &chan_info); for (i = 0; i < chan_info.cl_nchans; i++) { if (chan_info.cl_channels[i] == NULL) { DFS_PRINTK("%s: NULL channel\n", __func__); } else { chan_info.cl_channels[i]->ic_flagext |= CHANNEL_INTERFERENCE; dfs_nol_addchan(dfs, chan_info.cl_channels[i], dfs->ath_dfs_nol_timeout); } } /* * Update the umac/driver channels with the new NOL information. */ dfs_nol_update(dfs); } }
/* * Delete the given frequency/chwidth from the NOL. */ static void dfs_nol_delete(struct ath_dfs *dfs, u_int16_t delfreq, u_int16_t delchwidth) { struct dfs_nolelem *nol,**prev_next; if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL\n", __func__); return; } DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: remove channel=%d/%d MHz from NOL\n", __func__, delfreq, delchwidth); prev_next = &(dfs->dfs_nol); nol = dfs->dfs_nol; while (nol != NULL) { if (nol->nol_freq == delfreq && nol->nol_chwidth == delchwidth) { *prev_next = nol->nol_next; DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s removing channel %d/%dMHz from NOL tstamp=%d\n", __func__, nol->nol_freq, nol->nol_chwidth, (adf_os_ticks_to_msecs(adf_os_ticks()) / 1000)); OS_CANCEL_TIMER(&nol->nol_timer); OS_FREE(nol); nol = NULL; nol = *prev_next; /* Update the NOL counter */ dfs->dfs_nol_count--; /* Be paranoid! */ if (dfs->dfs_nol_count < 0) { DFS_PRINTK("%s: dfs_nol_count < 0; eek!\n", __func__); dfs->dfs_nol_count = 0; } } else { prev_next = &(nol->nol_next); nol = nol->nol_next; } } }
/* * Calculate the channel centre in MHz. */ static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs) { uint32_t chan_centre; uint32_t chan_width; int chan_offset; /* * For now, just handle up to VHT80 correctly. */ if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) { DFS_PRINTK("%s: dfs->ic=%p, that or curchan is null?\n", __func__, dfs->ic); return (0); /* * For now, the only 11ac channel with freq1/freq2 setup is * VHT80. * * XXX should have a flag macro to check this! */ } else if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) { /* 11AC, so cfreq1/cfreq2 are setup */ /* * XXX if it's 80+80 this won't work - need to use seg * appropriately! */ chan_centre = dfs->ic->ic_ieee2mhz( dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1, dfs->ic->ic_curchan->ic_flags); } else { /* HT20/HT40 */ /* * XXX this is hard-coded - it should be 5 or 10 for * half/quarter appropriately. */ chan_width = 20; /* Grab default channel centre */ chan_centre = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D */ if (IEEE80211_IS_CHAN_11N_HT40PLUS(dfs->ic->ic_curchan) || dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40PLUS) chan_offset = chan_width; else if (IEEE80211_IS_CHAN_11N_HT40MINUS(dfs->ic->ic_curchan) || dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40MINUS) chan_offset = -chan_width; else chan_offset = 0; /* Calculate new _real_ channel centre */ chan_centre += (chan_offset / 2); } /* * XXX half/quarter rate support! */ /* Return ev_chan_centre in MHz */ return (chan_centre); }
int dfs_bin5_check(struct ath_dfs *dfs) { struct dfs_bin5radars *br; int index[DFS_MAX_B5_SIZE]; uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0, rssi_diff = 0, width_diff = 0, bursts = 0; uint32_t total_diff = 0, average_diff = 0, total_width = 0, average_width = 0, numevents = 0; uint64_t pri; if (dfs == NULL) { DFS_PRINTK("%s: ic_dfs is NULL\n", __func__); return 1; } for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) { br = &(dfs->dfs_b5radars[n]); DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "Num elems = %d\n", br->br_numelems); /* find a valid bin 5 pulse and use it as reference */ for (i1 = 0; i1 < br->br_numelems; i1++) { this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK); if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) && (br->br_elems[this].be_dur <= MAX_BIN5_DUR_MICROSEC)) { break; } } prev = this; for (i = i1 + 1; i < br->br_numelems; i++) { this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK); /* first make sure it is a bin 5 pulse by checking the duration */ if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC) || (br->br_elems[this].be_dur > MAX_BIN5_DUR_MICROSEC)) { continue; } /* Rule 1: 1000 <= PRI <= 2000 + some margin */ if (br->br_elems[this].be_ts >= br->br_elems[prev].be_ts) { pri = br->br_elems[this].be_ts - br->br_elems[prev].be_ts; } else { /* roll over case */ /* pri = (0xffffffffffffffff - br->br_elems[prev].be_ts) + br->br_elems[this].be_ts; */ pri = br->br_elems[this].be_ts; } DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, " pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu\n", (unsigned long long)pri, (unsigned long long)br->br_elems[this]. be_ts, (int)br->br_elems[this].be_dur, (int)br->br_elems[this].be_rssi, (unsigned long long)br->br_elems[prev]. be_ts); if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) && (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) { /* pri: pulse repitition interval in us */ /* Rule 2: pulse width of the pulses in the burst should be same (+/- margin) */ if (br->br_elems[this].be_dur >= br->br_elems[prev].be_dur) { width_diff = br->br_elems[this].be_dur - br->br_elems[prev].be_dur; } else { width_diff = br->br_elems[prev].be_dur - br->br_elems[this].be_dur; } if (width_diff <= DFS_BIN5_WIDTH_MARGIN) { /* Rule 3: RSSI of the pulses in the burst should be same (+/- margin) */ if (br->br_elems[this].be_rssi >= br->br_elems[prev].be_rssi) { rssi_diff = br->br_elems[this].be_rssi - br->br_elems[prev].be_rssi; } else { rssi_diff = br->br_elems[prev].be_rssi - br->br_elems[this].be_rssi; } if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) { bursts++; /* Save the indexes of this pair for later width variance check */ if (numevents >= 2) { /* make sure the event is not duplicated, * possible in a 3 pulse burst */ if (index[numevents - 1] != prev) { index [numevents++] = prev; } } else { index[numevents++] = prev; } index[numevents++] = this; } else { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "%s %d Bin5 rssi_diff=%d\n", __func__, __LINE__, rssi_diff); } } else { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "%s %d Bin5 width_diff=%d\n", __func__, __LINE__, width_diff); } } else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) && (pri <= DFS_BIN5_BRI_UPPER_LIMIT)) { /* check pulse width to make sure it is in range of bin 5 */ /* if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) && (br->br_elems[this].be_dur <= MAX_BIN5_DUR_MICROSEC)) { */ bursts++; /* } */ } else { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "%s %d Bin5 PRI check fail pri=%llu\n", __func__, __LINE__, (unsigned long long)pri); } prev = this; } DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u\n", bursts, numevents); if (bursts >= br->br_pulse.b5_threshold) { if ((br->br_elems[br->br_lastelem].be_ts - br->br_elems[br->br_firstelem].be_ts) < 3000000) { return 0; } else { /* * don't do this check since not all the cases have this kind of burst width variation. * for (i=0; i<bursts; i++){ total_width += br->br_elems[index[i]].be_dur; } average_width = total_width/bursts; for (i=0; i<bursts; i++){ total_diff += DFS_DIFF(br->br_elems[index[i]].be_dur, average_width); } average_diff = total_diff/bursts; if( average_diff > DFS_BIN5_WIDTH_MARGIN ) { return 1; } else { DFS_DPRINTK(ic, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", bursts, numevents, total_width, average_width, total_diff, average_diff); } */ DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", bursts, numevents, total_width, average_width, total_diff, average_diff); DFS_PRINTK("bin 5 radar detected, bursts=%d\n", bursts); return 1; } } } return 0; }
/* * This is called each time a channel change occurs, to (potentially) enable * the radar code. */ int dfs_radar_enable(struct ieee80211com *ic, struct ath_dfs_radar_tab_info *radar_info, int no_cac) { int is_ext_ch=IEEE80211_IS_CHAN_11N_HT40(ic->ic_curchan); int is_fastclk = 0; //u_int32_t rfilt; struct ath_dfs *dfs=(struct ath_dfs *)ic->ic_dfs; struct ieee80211_channel *chan=ic->ic_curchan, *ext_ch = NULL; if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: ic_dfs is NULL\n", __func__); return -EIO; } ic->ic_dfs_disable(ic, no_cac); /* * Setting country code might change the DFS domain * so initialize the DFS Radar filters */ dfs_init_radar_filters(ic, radar_info); #if ATH_SUPPORT_DFS && ATH_SUPPORT_STA_DFS if ((ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS || (ic->ic_opmode == IEEE80211_M_STA && ieee80211com_has_cap_ext(dfs->ic,IEEE80211_CEXT_STADFS)))) { #else if ((ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS)) { #endif if (IEEE80211_IS_CHAN_DFS(chan)) { struct dfs_state *rs_pri=NULL, *rs_ext=NULL; u_int8_t index_pri, index_ext; #ifdef ATH_ENABLE_AR dfs->dfs_proc_phyerr |= DFS_AR_EN; #endif dfs->dfs_proc_phyerr |= DFS_RADAR_EN; //printk( "%s[%d]: ==== 0x%08x\n", __func__, __LINE__, dfs->dfs_proc_phyerr); if (is_ext_ch) { ext_ch = ieee80211_get_extchan(ic); } dfs_reset_alldelaylines(dfs); rs_pri = dfs_getchanstate(dfs, &index_pri, 0); if (ext_ch) { rs_ext = dfs_getchanstate(dfs, &index_ext, 1); } if (rs_pri != NULL && ((ext_ch==NULL)||(rs_ext != NULL))) { struct ath_dfs_phyerr_param pe; OS_MEMSET(&pe, '\0', sizeof(pe)); if (index_pri != dfs->dfs_curchan_radindex) dfs_reset_alldelaylines(dfs); dfs->dfs_curchan_radindex = (int16_t) index_pri; if (rs_ext) dfs->dfs_extchan_radindex = (int16_t) index_ext; ath_dfs_phyerr_param_copy(&pe, &rs_pri->rs_param); DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, "%s: firpwr=%d, rssi=%d, height=%d, " "prssi=%d, inband=%d, relpwr=%d, " "relstep=%d, maxlen=%d\n", __func__, pe.pe_firpwr, pe.pe_rrssi, pe.pe_height, pe.pe_prssi, pe.pe_inband, pe.pe_relpwr, pe.pe_relstep, pe.pe_maxlen ); #if 0 //Not needed /* Disable strong signal fast antenna diversity */ ath_hal_setcapability(ah, HAL_CAP_DIVERSITY, HAL_CAP_STRONG_DIV, 1, NULL); #endif ic->ic_dfs_enable(ic, &is_fastclk, &pe); DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "Enabled radar detection on channel %d\n", chan->ic_freq); dfs->dur_multiplier = is_fastclk ? DFS_FAST_CLOCK_MULTIPLIER : DFS_NO_FAST_CLOCK_MULTIPLIER; DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, "%s: duration multiplier is %d\n", __func__, dfs->dur_multiplier); } else DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: No more radar states left\n", __func__); } } return 0; } int dfs_control(struct ieee80211com *ic, u_int id, void *indata, u_int32_t insize, void *outdata, u_int32_t *outsize) { int error = 0; struct ath_dfs_phyerr_param peout; struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; struct dfs_ioctl_params *dfsparams; u_int32_t val=0; #ifndef ATH_DFS_RADAR_DETECTION_ONLY struct dfsreq_nolinfo *nol; u_int32_t *data = NULL; #endif /* ATH_DFS_RADAR_DETECTION_ONLY */ int i; if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s DFS is null\n", __func__); /* Enable/Disable DFS can be done prior to attach, So handle here */ switch (id) { case DFS_DISABLE_DETECT: ic->ic_dfs_state.ignore_dfs = 1; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, ic->ic_dfs_state.ignore_dfs ? 1:0); break; case DFS_ENABLE_DETECT: ic->ic_dfs_state.ignore_dfs = 0; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, ic->ic_dfs_state.ignore_dfs ? 1:0); break; default: error = -EINVAL; break; } goto bad; } //printk("%s[%d] id =%d\n", __func__, __LINE__, id); switch (id) { case DFS_SET_THRESH: if (insize < sizeof(struct dfs_ioctl_params) || !indata) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: insize=%d, expected=%d bytes, indata=%p\n", __func__, insize, sizeof(struct dfs_ioctl_params), indata); error = -EINVAL; break; } dfsparams = (struct dfs_ioctl_params *) indata; if (!dfs_set_thresholds(ic, DFS_PARAM_FIRPWR, dfsparams->dfs_firpwr)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_RRSSI, dfsparams->dfs_rrssi)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_HEIGHT, dfsparams->dfs_height)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_PRSSI, dfsparams->dfs_prssi)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_INBAND, dfsparams->dfs_inband)) error = -EINVAL; /* 5413 speicfic */ if (!dfs_set_thresholds(ic, DFS_PARAM_RELPWR, dfsparams->dfs_relpwr)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_RELSTEP, dfsparams->dfs_relstep)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_MAXLEN, dfsparams->dfs_maxlen)) error = -EINVAL; break; case DFS_GET_THRESH: if (!outdata || !outsize || *outsize <sizeof(struct dfs_ioctl_params)) { error = -EINVAL; break; } *outsize = sizeof(struct dfs_ioctl_params); dfsparams = (struct dfs_ioctl_params *) outdata; /* * Fetch the DFS thresholds using the internal representation. */ (void) dfs_get_thresholds(ic, &peout); /* * Convert them to the dfs IOCTL representation. */ ath_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); break; case DFS_RADARDETECTS: if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) { error = -EINVAL; break; } *outsize = sizeof (u_int32_t); *((u_int32_t *)outdata) = dfs->ath_dfs_stats.num_radar_detects; break; case DFS_DISABLE_DETECT: dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; dfs->ic->ic_dfs_state.ignore_dfs = 1; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, dfs->ic->ic_dfs_state.ignore_dfs ? 1:0); break; case DFS_ENABLE_DETECT: dfs->dfs_proc_phyerr |= DFS_RADAR_EN; dfs->ic->ic_dfs_state.ignore_dfs = 0; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, dfs->ic->ic_dfs_state.ignore_dfs ? 1:0); break; case DFS_DISABLE_FFT: //UMACDFS: TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, false); DFS_PRINTK("%s TODO disable FFT val=0x%x \n", __func__, val); break; case DFS_ENABLE_FFT: //UMACDFS TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, true); DFS_PRINTK("%s TODO enable FFT val=0x%x \n", __func__, val); break; case DFS_SET_DEBUG_LEVEL: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->dfs_debug_mask= *(u_int32_t *)indata; DFS_PRINTK("%s debug level now = 0x%x \n", __func__, dfs->dfs_debug_mask); if (dfs->dfs_debug_mask & ATH_DEBUG_DFS3) { /* Enable debug Radar Event */ dfs->dfs_event_log_on = 1; } else { dfs->dfs_event_log_on = 0; } break; case DFS_SET_FALSE_RSSI_THRES: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->ath_dfs_false_rssi_thres= *(u_int32_t *)indata; DFS_PRINTK("%s false RSSI threshold now = 0x%x \n", __func__, dfs->ath_dfs_false_rssi_thres); break; case DFS_SET_PEAK_MAG: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->ath_dfs_peak_mag= *(u_int32_t *)indata; DFS_PRINTK("%s peak_mag now = 0x%x \n", __func__, dfs->ath_dfs_peak_mag); break; case DFS_GET_CAC_VALID_TIME: if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) { error = -EINVAL; break; } *outsize = sizeof (u_int32_t); *((u_int32_t *)outdata) = dfs->ic->ic_dfs_state.cac_valid_time; break; case DFS_SET_CAC_VALID_TIME: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->ic->ic_dfs_state.cac_valid_time = *(u_int32_t *)indata; DFS_PRINTK("%s dfs timeout = %d \n", __func__, dfs->ic->ic_dfs_state.cac_valid_time); break; case DFS_IGNORE_CAC: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } if (*(u_int32_t *)indata) { dfs->ic->ic_dfs_state.ignore_cac= 1; } else { dfs->ic->ic_dfs_state.ignore_cac= 0; } DFS_PRINTK("%s ignore cac = 0x%x \n", __func__, dfs->ic->ic_dfs_state.ignore_cac); break; case DFS_SET_NOL_TIMEOUT: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } if (*(int *)indata) { dfs->ath_dfs_nol_timeout= *(int *)indata; } else { dfs->ath_dfs_nol_timeout= DFS_NOL_TIMEOUT_S; } DFS_PRINTK("%s nol timeout = %d sec \n", __func__, dfs->ath_dfs_nol_timeout); break; #ifndef ATH_DFS_RADAR_DETECTION_ONLY case DFS_MUTE_TIME: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } data = (u_int32_t *) indata; dfs->ath_dfstesttime = *data; dfs->ath_dfstesttime *= (1000); //convert sec into ms break; case DFS_GET_USENOL: if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) { error = -EINVAL; break; } *outsize = sizeof(u_int32_t); *((u_int32_t *)outdata) = dfs->dfs_rinfo.rn_use_nol; printk("%s:#Phyerr=%d, #false detect=%d, #queued=%d\n", __func__,dfs->dfs_phyerr_count, dfs->dfs_phyerr_reject_count, dfs->dfs_phyerr_queued_count); printk("%s:dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d\n", __func__,dfs->dfs_phyerr_freq_min, dfs->dfs_phyerr_freq_max); printk("%s:Total radar events detected=%d, entries in the radar queue follows:\n", __func__,dfs->dfs_event_log_count); for (i = 0; (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count); i++) { //DFS_DPRINTK(sc, ATH_DEBUG_DFS,"ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); printk("ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); } dfs->dfs_event_log_count = 0; dfs->dfs_phyerr_count = 0; dfs->dfs_phyerr_reject_count = 0; dfs->dfs_phyerr_queued_count = 0; dfs->dfs_phyerr_freq_min = 0x7fffffff; dfs->dfs_phyerr_freq_max = 0; break; case DFS_SET_USENOL: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->dfs_rinfo.rn_use_nol = *(u_int32_t *)indata; /* iwpriv markdfs in linux can do the same thing... */ break; case DFS_GET_NOL: if (!outdata || !outsize || *outsize < sizeof(struct dfsreq_nolinfo)) { error = -EINVAL; break; } *outsize = sizeof(struct dfsreq_nolinfo); nol = (struct dfsreq_nolinfo *)outdata; dfs_get_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, &nol->ic_nchans); dfs_print_nol(dfs); break; case DFS_SET_NOL: if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { error = -EINVAL; break; } nol = (struct dfsreq_nolinfo *) indata; dfs_set_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, nol->ic_nchans); break; case DFS_SHOW_NOL: dfs_print_nol(dfs); break; #if ATH_SUPPORT_DFS && ATH_SUPPORT_STA_DFS case DFS_SHOW_NOLHISTORY: dfs_print_nolhistory(ic,dfs); break; #endif case DFS_BANGRADAR: #if 0 //MERGE_TBD if(sc->sc_nostabeacons) { printk("No radar detection Enabled \n"); break; } #endif dfs->dfs_bangradar = 1; dfs->ath_radar_tasksched = 1; OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); break; #endif /* ATH_DFS_RADAR_DETECTION_ONLY */ default: error = -EINVAL; } bad: return error; }
int dfs_attach(struct ieee80211com *ic) { int i, n; struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; struct ath_dfs_radar_tab_info radar_info; #define N(a) (sizeof(a)/sizeof(a[0])) if (dfs != NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs was not NULL\n", __func__); return 1; } if (ic->ic_dfs_state.ignore_dfs) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ignoring dfs\n", __func__); return 0; } dfs = (struct ath_dfs *)OS_MALLOC(ic->ic_osdev, sizeof(struct ath_dfs), GFP_ATOMIC); if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ath_dfs allocation failed\n", __func__); return 1; } OS_MEMZERO(dfs, sizeof (struct ath_dfs)); ic->ic_dfs = (void *)dfs; dfs->ic = ic; ic->ic_dfs_debug = dfs_get_debug_info; #ifndef ATH_DFS_RADAR_DETECTION_ONLY dfs->dfs_nol = NULL; #endif /* * Zero out radar_info. It's possible that the attach function won't * fetch an initial regulatory configuration; you really do want to * ensure that the contents indicates there aren't any filters. */ OS_MEMZERO(&radar_info, sizeof(radar_info)); ic->ic_dfs_attach(ic, &dfs->dfs_caps, &radar_info); dfs_clear_stats(ic); dfs->dfs_event_log_on = 0; OS_INIT_TIMER(ic->ic_osdev, &(dfs->ath_dfs_task_timer), dfs_task, (void *) (ic)); #ifndef ATH_DFS_RADAR_DETECTION_ONLY OS_INIT_TIMER(ic->ic_osdev, &(dfs->ath_dfstesttimer), dfs_testtimer_task, (void *) ic); dfs->ath_dfs_cac_time = ATH_DFS_WAIT_MS; dfs->ath_dfstesttime = ATH_DFS_TEST_RETURN_PERIOD_MS; #endif ATH_DFSQ_LOCK_INIT(dfs); STAILQ_INIT(&dfs->dfs_radarq); ATH_ARQ_LOCK_INIT(dfs); STAILQ_INIT(&dfs->dfs_arq); STAILQ_INIT(&(dfs->dfs_eventq)); ATH_DFSEVENTQ_LOCK_INIT(dfs); dfs->events = (struct dfs_event *)OS_MALLOC(ic->ic_osdev, sizeof(struct dfs_event)*DFS_MAX_EVENTS, GFP_ATOMIC); if (dfs->events == NULL) { OS_FREE(dfs); ic->ic_dfs = NULL; DFS_PRINTK("%s: events allocation failed\n", __func__); return 1; } for (i = 0; i < DFS_MAX_EVENTS; i++) { STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i], re_list); } dfs->pulses = (struct dfs_pulseline *)OS_MALLOC(ic->ic_osdev, sizeof(struct dfs_pulseline), GFP_ATOMIC); if (dfs->pulses == NULL) { OS_FREE(dfs->events); dfs->events = NULL; OS_FREE(dfs); ic->ic_dfs = NULL; DFS_PRINTK("%s: pulse buffer allocation failed\n", __func__); return 1; } dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; /* Allocate memory for radar filters */ for (n=0; n<DFS_MAX_RADAR_TYPES; n++) { dfs->dfs_radarf[n] = (struct dfs_filtertype *)OS_MALLOC(ic->ic_osdev, sizeof(struct dfs_filtertype),GFP_ATOMIC); if (dfs->dfs_radarf[n] == NULL) { DFS_PRINTK("%s: cannot allocate memory for radar filter types\n", __func__); goto bad1; } OS_MEMZERO(dfs->dfs_radarf[n], sizeof(struct dfs_filtertype)); } /* Allocate memory for radar table */ dfs->dfs_radartable = (int8_t **)OS_MALLOC(ic->ic_osdev, 256*sizeof(int8_t *), GFP_ATOMIC); if (dfs->dfs_radartable == NULL) { DFS_PRINTK("%s: cannot allocate memory for radar table\n", __func__); goto bad1; } for (n=0; n<256; n++) { dfs->dfs_radartable[n] = OS_MALLOC(ic->ic_osdev, DFS_MAX_RADAR_OVERLAP*sizeof(int8_t), GFP_ATOMIC); if (dfs->dfs_radartable[n] == NULL) { DFS_PRINTK("%s: cannot allocate memory for radar table entry\n", __func__); goto bad2; } } if (usenol == 0) DFS_PRINTK("%s: NOL disabled\n", __func__); else if (usenol == 2) DFS_PRINTK("%s: NOL disabled; no CSA\n", __func__); dfs->dfs_rinfo.rn_use_nol = usenol; /* Init the cached extension channel busy for false alarm reduction */ dfs->dfs_rinfo.ext_chan_busy_ts = ic->ic_get_TSF64(ic); dfs->dfs_rinfo.dfs_ext_chan_busy = 0; /* Init the Bin5 chirping related data */ dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts; dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR; dfs->dfs_b5radars = NULL; /* * If dfs_init_radar_filters() fails, we can abort here and * reconfigure when the first valid channel + radar config * is available. */ if ( dfs_init_radar_filters( ic, &radar_info) ) { DFS_PRINTK(" %s: Radar Filter Intialization Failed \n", __func__); return 1; } dfs->ath_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE; dfs->ath_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH; dfs->dfs_phyerr_freq_min = 0x7fffffff; dfs->dfs_phyerr_freq_max = 0; dfs->dfs_phyerr_queued_count = 0; dfs->dfs_phyerr_w53_counter = 0; dfs->dfs_pri_multiplier = 2; dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; return 0; bad2: OS_FREE(dfs->dfs_radartable); dfs->dfs_radartable = NULL; bad1: for (n=0; n<DFS_MAX_RADAR_TYPES; n++) { if (dfs->dfs_radarf[n] != NULL) { OS_FREE(dfs->dfs_radarf[n]); dfs->dfs_radarf[n] = NULL; } } if (dfs->pulses) { OS_FREE(dfs->pulses); dfs->pulses = NULL; } if (dfs->events) { OS_FREE(dfs->events); dfs->events = NULL; } if (ic->ic_dfs) { OS_FREE(ic->ic_dfs); ic->ic_dfs = NULL; } return 1; #undef N }
/* * Notify the driver/umac that it should update the channel radar/NOL * flags based on the current NOL list. */ void dfs_nol_update(struct ath_dfs *dfs) { struct ieee80211com *ic = dfs->ic; struct dfs_nol_chan_entry *dfs_nol; struct dfs_nolelem *nol; int nlen; /* * Allocate enough entries to store the NOL. * * At least on Linux (don't ask why), if you allocate a 0 entry * array, the returned pointer is 0x10. Make sure you're * aware of this when you start debugging. */ dfs_nol = (struct dfs_nol_chan_entry *)OS_MALLOC(dfs->ic->ic_osdev, sizeof(struct dfs_nol_chan_entry) * dfs->dfs_nol_count, GFP_ATOMIC); if (dfs_nol == NULL) { /* * XXX TODO: if this fails, just schedule a task to retry * updating the NOL at a later stage. That way the NOL * update _DOES_ happen - hopefully the failure was just * temporary. */ DFS_PRINTK("%s: failed to allocate NOL update memory!\n", __func__); return; } /* populate the nol array */ nlen = 0; nol = dfs->dfs_nol; while (nol != NULL && nlen < dfs->dfs_nol_count) { dfs_nol[nlen].nol_chfreq = nol->nol_freq; dfs_nol[nlen].nol_chwidth = nol->nol_chwidth; dfs_nol[nlen].nol_start_ticks = nol->nol_start_ticks; dfs_nol[nlen].nol_timeout_ms = nol->nol_timeout_ms; nlen++; nol = nol->nol_next; } /* Be suitably paranoid for now */ if (nlen != dfs->dfs_nol_count) DFS_PRINTK("%s: nlen (%d) != dfs->dfs_nol_count (%d)!\n", __func__, nlen, dfs->dfs_nol_count); /* * Call the driver layer to have it recalculate the NOL flags for * each driver/umac channel. * * If the list is empty, pass NULL instead of dfs_nol. * * The operating system may have some special representation for * "malloc a 0 byte memory region" - for example, * Linux 2.6.38-13 (ubuntu) returns 0x10 rather than a valid * allocation (and is likely not NULL so the pointer doesn't * match NULL checks in any later code. */ ic->ic_dfs_clist_update(ic, DFS_NOL_CLIST_CMD_UPDATE, (nlen > 0) ? dfs_nol : NULL, nlen); /* * .. and we're done. */ OS_FREE(dfs_nol); }
int dfs_control(struct ieee80211com *ic, u_int id, void *indata, u_int32_t insize, void *outdata, u_int32_t *outsize) { int error = 0; struct ath_dfs_phyerr_param peout; struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; struct dfs_ioctl_params *dfsparams; u_int32_t val=0; #ifndef ATH_DFS_RADAR_DETECTION_ONLY struct dfsreq_nolinfo *nol; u_int32_t *data = NULL; #endif /* ATH_DFS_RADAR_DETECTION_ONLY */ int i; if (dfs == NULL) { error = -EINVAL; DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s DFS is null\n", __func__); goto bad; } switch (id) { case DFS_SET_THRESH: if (insize < sizeof(struct dfs_ioctl_params) || !indata) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: insize=%d, expected=%zu bytes, indata=%p\n", __func__, insize, sizeof(struct dfs_ioctl_params), indata); error = -EINVAL; break; } dfsparams = (struct dfs_ioctl_params *) indata; if (!dfs_set_thresholds(ic, DFS_PARAM_FIRPWR, dfsparams->dfs_firpwr)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_RRSSI, dfsparams->dfs_rrssi)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_HEIGHT, dfsparams->dfs_height)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_PRSSI, dfsparams->dfs_prssi)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_INBAND, dfsparams->dfs_inband)) error = -EINVAL; /* 5413 speicfic */ if (!dfs_set_thresholds(ic, DFS_PARAM_RELPWR, dfsparams->dfs_relpwr)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_RELSTEP, dfsparams->dfs_relstep)) error = -EINVAL; if (!dfs_set_thresholds(ic, DFS_PARAM_MAXLEN, dfsparams->dfs_maxlen)) error = -EINVAL; break; case DFS_GET_THRESH: if (!outdata || !outsize || *outsize <sizeof(struct dfs_ioctl_params)) { error = -EINVAL; break; } *outsize = sizeof(struct dfs_ioctl_params); dfsparams = (struct dfs_ioctl_params *) outdata; /* * Fetch the DFS thresholds using the internal representation. */ (void) dfs_get_thresholds(ic, &peout); /* * Convert them to the dfs IOCTL representation. */ ath_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); break; case DFS_RADARDETECTS: if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) { error = -EINVAL; break; } *outsize = sizeof (u_int32_t); *((u_int32_t *)outdata) = dfs->ath_dfs_stats.num_radar_detects; break; case DFS_DISABLE_DETECT: dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; dfs->ic->ic_dfs_state.ignore_dfs = 1; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, dfs->ic->ic_dfs_state.ignore_dfs); break; case DFS_ENABLE_DETECT: dfs->dfs_proc_phyerr |= DFS_RADAR_EN; dfs->ic->ic_dfs_state.ignore_dfs = 0; DFS_PRINTK("%s enable detects, ignore_dfs %d\n", __func__, dfs->ic->ic_dfs_state.ignore_dfs); break; case DFS_DISABLE_FFT: //UMACDFS: TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, false); DFS_PRINTK("%s TODO disable FFT val=0x%x \n", __func__, val); break; case DFS_ENABLE_FFT: //UMACDFS TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, true); DFS_PRINTK("%s TODO enable FFT val=0x%x \n", __func__, val); break; case DFS_SET_DEBUG_LEVEL: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->dfs_debug_mask= *(u_int32_t *)indata; DFS_PRINTK("%s debug level now = 0x%x \n", __func__, dfs->dfs_debug_mask); if (dfs->dfs_debug_mask & ATH_DEBUG_DFS3) { /* Enable debug Radar Event */ dfs->dfs_event_log_on = 1; } else { dfs->dfs_event_log_on = 0; } break; case DFS_SET_FALSE_RSSI_THRES: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->ath_dfs_false_rssi_thres= *(u_int32_t *)indata; DFS_PRINTK("%s false RSSI threshold now = 0x%x \n", __func__, dfs->ath_dfs_false_rssi_thres); break; case DFS_SET_PEAK_MAG: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->ath_dfs_peak_mag= *(u_int32_t *)indata; DFS_PRINTK("%s peak_mag now = 0x%x \n", __func__, dfs->ath_dfs_peak_mag); break; case DFS_IGNORE_CAC: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } if (*(u_int32_t *)indata) { dfs->ic->ic_dfs_state.ignore_cac= 1; } else { dfs->ic->ic_dfs_state.ignore_cac= 0; } DFS_PRINTK("%s ignore cac = 0x%x \n", __func__, dfs->ic->ic_dfs_state.ignore_cac); break; case DFS_SET_NOL_TIMEOUT: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } if (*(int *)indata) { dfs->ath_dfs_nol_timeout= *(int *)indata; } else { dfs->ath_dfs_nol_timeout= DFS_NOL_TIMEOUT_S; } DFS_PRINTK("%s nol timeout = %d sec \n", __func__, dfs->ath_dfs_nol_timeout); break; #ifndef ATH_DFS_RADAR_DETECTION_ONLY case DFS_MUTE_TIME: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } data = (u_int32_t *) indata; dfs->ath_dfstesttime = *data; dfs->ath_dfstesttime *= (1000); //convert sec into ms break; case DFS_GET_USENOL: if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) { error = -EINVAL; break; } *outsize = sizeof(u_int32_t); *((u_int32_t *)outdata) = dfs->dfs_rinfo.rn_use_nol; for (i = 0; (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count); i++) { //DFS_DPRINTK(sc, ATH_DEBUG_DFS,"ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); } dfs->dfs_event_log_count = 0; dfs->dfs_phyerr_count = 0; dfs->dfs_phyerr_reject_count = 0; dfs->dfs_phyerr_queued_count = 0; dfs->dfs_phyerr_freq_min = 0x7fffffff; dfs->dfs_phyerr_freq_max = 0; break; case DFS_SET_USENOL: if (insize < sizeof(u_int32_t) || !indata) { error = -EINVAL; break; } dfs->dfs_rinfo.rn_use_nol = *(u_int32_t *)indata; /* iwpriv markdfs in linux can do the same thing... */ break; case DFS_GET_NOL: if (!outdata || !outsize || *outsize < sizeof(struct dfsreq_nolinfo)) { error = -EINVAL; break; } *outsize = sizeof(struct dfsreq_nolinfo); nol = (struct dfsreq_nolinfo *)outdata; dfs_get_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, &nol->ic_nchans); dfs_print_nol(dfs); break; case DFS_SET_NOL: if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { error = -EINVAL; break; } nol = (struct dfsreq_nolinfo *) indata; dfs_set_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, nol->ic_nchans); break; case DFS_SHOW_NOL: dfs_print_nol(dfs); break; case DFS_BANGRADAR: #if 0 //MERGE_TBD if(sc->sc_nostabeacons) { printk("No radar detection Enabled \n"); break; } #endif dfs->dfs_bangradar = 1; dfs->ath_radar_tasksched = 1; OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); break; #endif /* ATH_DFS_RADAR_DETECTION_ONLY */ default: error = -EINVAL; } bad: return error; }