static void dumpchannels(struct ath_hal *ah, int nc, const struct ieee80211_channel *chans, int16_t *txpow) { int i; for (i = 0; i < nc; i++) { const struct ieee80211_channel *c = &chans[i]; int type; if (showchannels) printf("%s%3d", sep, ath_hal_mhz2ieee(ah, c->ic_freq, c->ic_flags)); else printf("%s%u", sep, c->ic_freq); if (IEEE80211_IS_CHAN_HALF(c)) type = 'H'; else if (IEEE80211_IS_CHAN_QUARTER(c)) type = 'Q'; else if (IEEE80211_IS_CHAN_TURBO(c)) type = 'T'; else if (IEEE80211_IS_CHAN_HT(c)) type = 'N'; else if (IEEE80211_IS_CHAN_A(c)) type = 'A'; else if (IEEE80211_IS_CHAN_108G(c)) type = 'T'; else if (IEEE80211_IS_CHAN_G(c)) type = 'G'; else type = 'B'; if (dopassive && IEEE80211_IS_CHAN_PASSIVE(c)) type = tolower(type); if (isdfs && is4ms) printf("%c%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (isdfs) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_DFS(c) ? '*' : ' ', txpow[i]/2, (txpow[i]%2)*5); else if (is4ms) printf("%c%c %d.%d", type, IEEE80211_IS_CHAN_4MS(c) ? '4' : ' ', txpow[i]/2, (txpow[i]%2)*5); else printf("%c %d.%d", type, txpow[i]/2, (txpow[i]%2)*5); if ((n++ % (showchannels ? 7 : 6)) == 0) sep = "\n"; else sep = " "; } }
/* * Enable radar check */ void ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan) { /* Check if the current channel is radar-enabled */ if (! IEEE80211_IS_CHAN_DFS(chan)) return; }
/* Implement wmi_unified_vdev_start_cmd() here */ static int _ieee80211_resmgr_vap_start(ieee80211_resmgr_t resmgr, ieee80211_vap_t vap, struct ieee80211_channel *chan, u_int16_t reqid, u_int16_t max_start_time) { struct ieee80211com *ic = resmgr->ic; struct ol_ath_softc_net80211 *scn = OL_ATH_SOFTC_NET80211(ic); struct ol_ath_vap_net80211 *avn = OL_ATH_VAP_NET80211(vap); u_int32_t freq; bool disable_hw_ack= false; printk("OL vap_start +\n"); freq = ieee80211_chan2freq(resmgr->ic, chan); if (!freq) { printk("ERROR : INVALID Freq \n"); return 0; } #if ATH_SUPPORT_DFS if ( vap->iv_opmode == IEEE80211_M_HOSTAP && IEEE80211_IS_CHAN_DFS(chan)) { disable_hw_ack = true; } #endif /* BUG : Seen on AKronite, VDEV Start event response comes before setting * av_ol_resmgr_wait to TRUE, this make VAP not coming up issue. * Hence moving below assignment before sending VDEV_START_CMD_ID to target */ /* Interface is up, UMAC is waiting for * target response */ avn->av_ol_resmgr_wait = TRUE; spin_lock(&vap->init_lock); if (wmi_unified_vdev_start_send(scn->wmi_handle, avn->av_if_id, chan, freq, disable_hw_ack)) { printk("Unable to bring up the interface for ath_dev.\n"); spin_unlock(&vap->init_lock); return -1; } /* The channel configured in target is not same always with the vap desired channel due to 20/40 coexistence scenarios, so, channel is saved to configure on VDEV START RESP */ avn->av_ol_resmgr_chan = chan; vap->init_in_progress = true; spin_unlock(&vap->init_lock); printk("OL vap_start -\n"); return EBUSY; }
/* * Enable radar check. Return 1 if the driver should * enable radar PHY errors, or 0 if not. */ int ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan) { #if 0 HAL_PHYERR_PARAM pe; /* Check if the hardware supports radar reporting */ /* XXX TODO: migrate HAL_CAP_RADAR/HAL_CAP_AR to somewhere public! */ if (ath_hal_getcapability(sc->sc_ah, HAL_CAP_PHYDIAG, 0, NULL) != HAL_OK) return (0); /* Check if the current channel is radar-enabled */ if (! IEEE80211_IS_CHAN_DFS(chan)) return (0); /* Fetch the default parameters */ memset(&pe, '\0', sizeof(pe)); if (! ath_hal_getdfsdefaultthresh(sc->sc_ah, &pe)) return (0); /* Enable radar PHY error reporting */ sc->sc_dodfs = 1; /* Tell the hardware to enable radar reporting */ pe.pe_enabled = 1; /* Flip on extension channel events only if doing HT40 */ if (IEEE80211_IS_CHAN_HT40(chan)) pe.pe_extchannel = 1; else pe.pe_extchannel = 0; ath_hal_enabledfs(sc->sc_ah, &pe); /* * Disable strong signal fast diversity - needed for * AR5212 and similar PHYs for reliable short pulse * duration. */ (void) ath_hal_setcapability(sc->sc_ah, HAL_CAP_DIVERSITY, 2, 0, NULL); return (1); #else return (0); #endif }
void dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen, uint8_t r_rssi, uint8_t r_ext_rssi, uint32_t r_rs_tstamp, uint64_t r_fulltsf, bool enable_log) { struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; struct dfs_ieee80211_channel *chan = ic->ic_curchan; struct dfs_event *event; struct dfs_phy_err e; int empty; if (dfs == NULL) { CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, "%s: sc_dfs is NULL\n", __func__); return; } dfs->dfs_phyerr_count++; dump_phyerr_contents(buf, datalen); /* * XXX The combined_rssi_ok support has been removed. * This was only clear for Owl. * * XXX TODO: re-add this; it requires passing in the ctl/ext * RSSI set from the RX status descriptor. * * XXX TODO TODO: this may be done for us from the legacy * phy error path in ath_dev; please review that code. */ /* * At this time we have a radar pulse that we need to examine and * queue. But if dfs_process_radarevent already detected radar and set * CHANNEL_INTERFERENCE flag then do not queue any more radar data. * When we are in a new channel this flag will be clear and we will * start queueing data for new channel. (EV74162) */ if (dfs->dfs_debug_mask & ATH_DEBUG_DFS_PHYERR_PKT) dump_phyerr_contents(buf, datalen); if (chan == NULL) { CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, "%s: chan is NULL\n", __func__); return; } cdf_spin_lock_bh(&ic->chan_lock); if (IEEE80211_IS_CHAN_RADAR(chan)) { cdf_spin_unlock_bh(&ic->chan_lock); DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: Radar already found in the channel, " " do not queue radar data\n", __func__); return; } cdf_spin_unlock_bh(&ic->chan_lock); dfs->ath_dfs_stats.total_phy_errors++; DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s[%d] phyerr %d len %d\n", __func__, __LINE__, dfs->ath_dfs_stats.total_phy_errors, datalen); /* * hardware stores this as 8 bit signed value. * we will cap it at 0 if it is a negative number */ if (r_rssi & 0x80) r_rssi = 0; if (r_ext_rssi & 0x80) r_ext_rssi = 0; OS_MEMSET(&e, 0, sizeof(e)); /* * This is a bit evil - instead of just passing in * the chip version, the existing code uses a set * of HAL capability bits to determine what is * possible. * * The way I'm decoding it is thus: * * + DFS enhancement? Merlin or later * + DFS extension channel? Sowl or later. (Howl?) * + otherwise, Owl (and legacy.) */ if (dfs->dfs_caps.ath_chip_is_bb_tlv) { if (dfs_process_phyerr_bb_tlv(dfs, buf, datalen, r_rssi, r_ext_rssi, r_rs_tstamp, r_fulltsf, &e, enable_log) == 0) { dfs->dfs_phyerr_reject_count++; return; } else { if (dfs->dfs_phyerr_freq_min > e.freq) dfs->dfs_phyerr_freq_min = e.freq; if (dfs->dfs_phyerr_freq_max < e.freq) dfs->dfs_phyerr_freq_max = e.freq; } } else if (dfs->dfs_caps.ath_dfs_use_enhancement) { if (dfs_process_phyerr_merlin(dfs, buf, datalen, r_rssi, r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) { return; } } else if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { if (dfs_process_phyerr_sowl(dfs, buf, datalen, r_rssi, r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) { return; } } else { if (dfs_process_phyerr_owl(dfs, buf, datalen, r_rssi, r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) { return; } } CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, "\n %s: Frequency at which the phyerror was injected = %d", __func__, e.freq); /* * If the hardware supports radar reporting on the extension channel * it will supply FFT data for longer radar pulses. * * TLV chips don't go through this software check - the hardware * check should be enough. If we want to do software checking * later on then someone will have to craft an FFT parser * suitable for the TLV FFT data format. */ if ((!dfs->dfs_caps.ath_chip_is_bb_tlv) && dfs->dfs_caps.ath_dfs_ext_chan_ok) { /* * HW has a known issue with chirping pulses injected at or * around DC in 40MHz mode. Such pulses are reported with * much lower durations and SW then discards them because * they do not fit the minimum bin5 pulse duration. * * To work around this issue, if a pulse is within a 10us * range of the bin5 min duration, check if the pulse is * chirping. If the pulse is chirping, bump up the duration * to the minimum bin5 duration. * * This makes sure that a valid chirping pulse will not be * discarded because of incorrect low duration. * * TBD - Is it possible to calculate the 'real' duration of * the pulse using the slope of the FFT data? * * TBD - Use FFT data to differentiate between radar pulses * and false PHY errors. * This will let us reduce the number of false alarms seen. * * BIN 5 chirping pulses are only for FCC or Japan MMK4 domain */ if (((dfs->dfsdomain == DFS_FCC_DOMAIN) || (dfs->dfsdomain == DFS_MKK4_DOMAIN)) && (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) { int add_dur; int slope = 0, dc_found = 0; /* * Set the event chirping flags; as we're doing * an actual chirp check. */ e.do_check_chirp = 1; e.is_hw_chirp = 0; e.is_sw_chirp = 0; /* * dfs_check_chirping() expects is_pri and is_ext * to be '1' for true and '0' for false for now, * as the function itself uses these values in * constructing things rather than testing them * for 'true' or 'false'. */ add_dur = dfs_check_chirping(dfs, buf, datalen, (e.is_pri ? 1 : 0), (e.is_ext ? 1 : 0), &slope, &dc_found); if (add_dur) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "old dur %d slope =%d\n", e.dur, slope); e.is_sw_chirp = 1; /* bump up to a random bin5 pulse duration */ if (e.dur < MIN_BIN5_DUR) { e.dur = dfs_get_random_bin5_dur(dfs, e.fulltsf); } DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "new dur %d\n", e.dur); } else { /* set the duration so that it is rejected */ e.is_sw_chirp = 0; e.dur = MAX_BIN5_DUR + 100; DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "is_chirping = %d dur=%d\n", add_dur, e.dur); } } else { /* * We have a pulse that is either bigger than * MAX_BIN5_DUR or * less than MAYBE_BIN5_DUR */ if ((dfs->dfsdomain == DFS_FCC_DOMAIN) || (dfs->dfsdomain == DFS_MKK4_DOMAIN)) { /* * XXX Would this result in very large pulses * wrapping around to become short pulses? */ if (e.dur >= MAX_BIN5_DUR) { /* * set the duration so that it is * rejected */ e.dur = MAX_BIN5_DUR + 50; } } } } /* * Add the parsed, checked and filtered entry to the radar pulse * event list. This is then checked by dfs_radar_processevent(). * * XXX TODO: some filtering is still done below this point - fix * XXX this! */ ATH_DFSEVENTQ_LOCK(dfs); empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); ATH_DFSEVENTQ_UNLOCK(dfs); if (empty) { return; } /* * If the channel is a turbo G channel, then the event is * for the adaptive radio (AR) pattern matching rather than * radar detection. */ cdf_spin_lock_bh(&ic->chan_lock); if ((chan->ic_flags & CHANNEL_108G) == CHANNEL_108G) { cdf_spin_unlock_bh(&ic->chan_lock); if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s: DFS_AR_EN not enabled\n", __func__); return; } ATH_DFSEVENTQ_LOCK(dfs); event = STAILQ_FIRST(&(dfs->dfs_eventq)); if (event == NULL) { ATH_DFSEVENTQ_UNLOCK(dfs); DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: no more events space left\n", __func__); return; } STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); ATH_DFSEVENTQ_UNLOCK(dfs); event->re_rssi = e.rssi; event->re_dur = e.dur; event->re_full_ts = e.fulltsf; event->re_ts = (e.rs_tstamp) & DFS_TSMASK; event->re_chanindex = dfs->dfs_curchan_radindex; event->re_flags = 0; event->sidx = e.sidx; /* * Handle chirp flags. */ if (e.do_check_chirp) { event->re_flags |= DFS_EVENT_CHECKCHIRP; if (e.is_hw_chirp) event->re_flags |= DFS_EVENT_HW_CHIRP; if (e.is_sw_chirp) event->re_flags |= DFS_EVENT_SW_CHIRP; } ATH_ARQ_LOCK(dfs); STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list); ATH_ARQ_UNLOCK(dfs); } else { if (IEEE80211_IS_CHAN_DFS(chan)) { cdf_spin_unlock_bh(&ic->chan_lock); if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, "%s: DFS_RADAR_EN not enabled\n", __func__); return; } /* * rssi is not accurate for short pulses, so do * not filter based on that for short duration pulses * * XXX do this filtering above? */ if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { if ((e.rssi < dfs->dfs_rinfo.rn_minrssithresh && (e.dur > 4)) || e.dur > (dfs->dfs_rinfo.rn_maxpulsedur)) { dfs->ath_dfs_stats.rssi_discards++; DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "Extension channel pulse is " "discarded: dur=%d, " "maxpulsedur=%d, rssi=%d, " "minrssi=%d\n", e.dur, dfs->dfs_rinfo. rn_maxpulsedur, e.rssi, dfs->dfs_rinfo. rn_minrssithresh); return; } } else { if (e.rssi < dfs->dfs_rinfo.rn_minrssithresh || e.dur > dfs->dfs_rinfo.rn_maxpulsedur) { /* XXX TODO add a debug statement? */ dfs->ath_dfs_stats.rssi_discards++; return; } } /* * Add the event to the list, if there's space. */ ATH_DFSEVENTQ_LOCK(dfs); event = STAILQ_FIRST(&(dfs->dfs_eventq)); if (event == NULL) { ATH_DFSEVENTQ_UNLOCK(dfs); DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: no more events space left\n", __func__); return; } STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); ATH_DFSEVENTQ_UNLOCK(dfs); dfs->dfs_phyerr_queued_count++; dfs->dfs_phyerr_w53_counter++; event->re_dur = e.dur; event->re_full_ts = e.fulltsf; event->re_ts = (e.rs_tstamp) & DFS_TSMASK; event->re_rssi = e.rssi; event->sidx = e.sidx; /* * Handle chirp flags. */ if (e.do_check_chirp) { event->re_flags |= DFS_EVENT_CHECKCHIRP; if (e.is_hw_chirp) event->re_flags |= DFS_EVENT_HW_CHIRP; if (e.is_sw_chirp) event->re_flags |= DFS_EVENT_SW_CHIRP; } /* * Correctly set which channel is being reported on */ if (e.is_pri) { event->re_chanindex = dfs->dfs_curchan_radindex; } else { if (dfs->dfs_extchan_radindex == -1) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s - phyerr on ext channel\n", __func__); } event->re_chanindex = dfs->dfs_extchan_radindex; DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s New extension channel event is added " "to queue\n", __func__); } ATH_DFSQ_LOCK(dfs); STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); ATH_DFSQ_UNLOCK(dfs); } else { cdf_spin_unlock_bh(&ic->chan_lock); } } /* * Schedule the radar/AR task as appropriate. * * XXX isn't a lock needed for ath_radar_tasksched? */ /* * Commenting out the dfs_process_ar_event() since the function is never * called at run time as dfs_arq will be empty and the function * dfs_process_ar_event is obsolete and function definition is removed * as part of dfs_ar.c file * * if (!STAILQ_EMPTY(&dfs->dfs_arq)) * // XXX shouldn't this be a task/timer too? * dfs_process_ar_event(dfs, ic->ic_curchan); */ if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->ath_radar_tasksched) { dfs->ath_radar_tasksched = 1; OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); } #undef EXT_CH_RADAR_FOUND #undef PRI_CH_RADAR_FOUND #undef EXT_CH_RADAR_EARLY_FOUND }
/* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * bChannelChange is used to preserve DMA/PCU registers across * a HW Reset during channel change. */ HAL_BOOL ar5312Reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL bChannelChange, HAL_RESET_TYPE resetType, HAL_STATUS *status) { #define N(a) (sizeof (a) / sizeof (a[0])) #define FAIL(_code) do { ecode = _code; goto bad; } while (0) struct ath_hal_5212 *ahp = AH5212(ah); HAL_CHANNEL_INTERNAL *ichan; const HAL_EEPROM *ee; uint32_t saveFrameSeqCount, saveDefAntenna; uint32_t macStaId1, synthDelay, txFrm2TxDStart; uint16_t rfXpdGain[MAX_NUM_PDGAINS_PER_CHANNEL]; int16_t cckOfdmPwrDelta = 0; u_int modesIndex, freqIndex; HAL_STATUS ecode; int i, regWrites = 0; uint32_t testReg; uint32_t saveLedState = 0; HALASSERT(ah->ah_magic == AR5212_MAGIC); ee = AH_PRIVATE(ah)->ah_eeprom; OS_MARK(ah, AH_MARK_RESET, bChannelChange); /* * Map public channel to private. */ ichan = ath_hal_checkchannel(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); FAIL(HAL_EINVAL); } switch (opmode) { case HAL_M_STA: case HAL_M_IBSS: case HAL_M_HOSTAP: case HAL_M_MONITOR: break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n", __func__, opmode); FAIL(HAL_EINVAL); break; } HALASSERT(ahp->ah_eeversion >= AR_EEPROM_VER3); /* Preserve certain DMA hardware registers on a channel change */ if (bChannelChange) { /* * On Venice, the TSF is almost preserved across a reset; * it requires the doubling writes to the RESET_TSF * bit in the AR_BEACON register; it also has the quirk * of the TSF going back in time on the station (station * latches onto the last beacon's tsf during a reset 50% * of the times); the latter is not a problem for adhoc * stations since as long as the TSF is behind, it will * get resynchronized on receiving the next beacon; the * TSF going backwards in time could be a problem for the * sleep operation (supported on infrastructure stations * only) - the best and most general fix for this situation * is to resynchronize the various sleep/beacon timers on * the receipt of the next beacon i.e. when the TSF itself * gets resynchronized to the AP's TSF - power save is * needed to be temporarily disabled until that time * * Need to save the sequence number to restore it after * the reset! */ saveFrameSeqCount = OS_REG_READ(ah, AR_D_SEQNUM); } else saveFrameSeqCount = 0; /* NB: silence compiler */ /* If the channel change is across the same mode - perform a fast channel change */ if ((IS_2413(ah) || IS_5413(ah))) { /* * Channel change can only be used when: * -channel change requested - so it's not the initial reset. * -it's not a change to the current channel - often called when switching modes * on a channel * -the modes of the previous and requested channel are the same - some ugly code for XR */ if (bChannelChange && AH_PRIVATE(ah)->ah_curchan != AH_NULL && (chan->ic_freq != AH_PRIVATE(ah)->ah_curchan->ic_freq) && ((chan->ic_flags & IEEE80211_CHAN_ALLTURBO) == (AH_PRIVATE(ah)->ah_curchan->ic_flags & IEEE80211_CHAN_ALLTURBO))) { if (ar5212ChannelChange(ah, chan)) /* If ChannelChange completed - skip the rest of reset */ return AH_TRUE; } } /* * Preserve the antenna on a channel change */ saveDefAntenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (saveDefAntenna == 0) /* XXX magic constants */ saveDefAntenna = 1; /* Save hardware flag before chip reset clears the register */ macStaId1 = OS_REG_READ(ah, AR_STA_ID1) & (AR_STA_ID1_BASE_RATE_11B | AR_STA_ID1_USE_DEFANT); /* Save led state from pci config register */ if (!IS_5315(ah)) saveLedState = OS_REG_READ(ah, AR5312_PCICFG) & (AR_PCICFG_LEDCTL | AR_PCICFG_LEDMODE | AR_PCICFG_LEDBLINK | AR_PCICFG_LEDSLOW); ar5312RestoreClock(ah, opmode); /* move to refclk operation */ /* * Adjust gain parameters before reset if * there's an outstanding gain updated. */ (void) ar5212GetRfgain(ah); if (!ar5312ChipReset(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } /* Setup the indices for the next set of register array writes */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; modesIndex = IEEE80211_IS_CHAN_108G(chan) ? 5 : IEEE80211_IS_CHAN_G(chan) ? 4 : 3; } else { freqIndex = 1; modesIndex = IEEE80211_IS_CHAN_ST(chan) ? 2 : 1; } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); regWrites = ath_hal_ini_write(ah, &ahp->ah_ini_modes, modesIndex, 0); regWrites = write_common(ah, &ahp->ah_ini_common, bChannelChange, regWrites); ahp->ah_rfHal->writeRegs(ah, modesIndex, freqIndex, regWrites); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) ar5212SetIFSTiming(ah, chan); /* Overwrite INI values for revised chipsets */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { /* ADC_CTL */ OS_REG_WRITE(ah, AR_PHY_ADC_CTL, SM(2, AR_PHY_ADC_CTL_OFF_INBUFGAIN) | SM(2, AR_PHY_ADC_CTL_ON_INBUFGAIN) | AR_PHY_ADC_CTL_OFF_PWDDAC | AR_PHY_ADC_CTL_OFF_PWDADC); /* TX_PWR_ADJ */ if (chan->channel == 2484) { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta - ee->ee_scaledCh14FilterCckDelta); } else { cckOfdmPwrDelta = SCALE_OC_DELTA(ee->ee_cckOfdmPwrDelta); } if (IEEE80211_IS_CHAN_G(chan)) { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, SM((ee->ee_cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_GAIN_DELTA) | SM((cckOfdmPwrDelta*-1), AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX)); } else { OS_REG_WRITE(ah, AR_PHY_TXPWRADJ, 0); } /* Add barker RSSI thresh enable as disabled */ OS_REG_CLR_BIT(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR); OS_REG_RMW_FIELD(ah, AR_PHY_DAG_CTRLCCK, AR_PHY_DAG_CTRLCCK_RSSI_THR, 2); /* Set the mute mask to the correct default */ OS_REG_WRITE(ah, AR_SEQ_MASK, 0x0000000F); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_3) { /* Clear reg to alllow RX_CLEAR line debug */ OS_REG_WRITE(ah, AR_PHY_BLUETOOTH, 0); } if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_4) { #ifdef notyet /* Enable burst prefetch for the data queues */ OS_REG_RMW_FIELD(ah, AR_D_FPCTL, ... ); /* Enable double-buffering */ OS_REG_CLR_BIT(ah, AR_TXCFG, AR_TXCFG_DBL_BUF_DIS); #endif } if (IS_5312_2_X(ah)) { /* ADC_CTRL */ OS_REG_WRITE(ah, AR_PHY_SIGMA_DELTA, SM(2, AR_PHY_SIGMA_DELTA_ADC_SEL) | SM(4, AR_PHY_SIGMA_DELTA_FILT2) | SM(0x16, AR_PHY_SIGMA_DELTA_FILT1) | SM(0, AR_PHY_SIGMA_DELTA_ADC_CLIP)); if (IEEE80211_IS_CHAN_2GHZ(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, AR_PHY_RXGAIN_TXRX_RF_MAX, 0x0F); /* CCK Short parameter adjustment in 11B mode */ if (IEEE80211_IS_CHAN_B(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_CCK_RXCTRL4, AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT, 12); /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x04); /* Increase 11A AGC Settling */ if (IEEE80211_IS_CHAN_A(chan)) OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_AGC, 32); } else { /* Set ADC/DAC select values */ OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); } /* Setup the transmit power values. */ if (!ar5212SetTransmitPower(ah, chan, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error init'ing transmit power\n", __func__); FAIL(HAL_EIO); } /* Write the analog registers */ if (!ahp->ah_rfHal->setRfRegs(ah, chan, modesIndex, rfXpdGain)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: ar5212SetRfRegs failed\n", __func__); FAIL(HAL_EIO); } /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan)) { if (IS_5413(ah) || AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER5_3) ar5212SetSpurMitigation(ah, chan); ar5212SetDeltaSlope(ah, chan); } /* Setup board specific options for EEPROM version 3 */ if (!ar5212SetBoardValues(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } /* Restore certain DMA hardware registers on a channel change */ if (bChannelChange) OS_REG_WRITE(ah, AR_D_SEQNUM, saveFrameSeqCount); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | ahp->ah_staId1Defaults ); ar5212SetOperatingMode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); /* Restore previous led state */ if (!IS_5315(ah)) OS_REG_WRITE(ah, AR5312_PCICFG, OS_REG_READ(ah, AR_PCICFG) | saveLedState); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); /* then our BSSID */ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); /* Restore bmiss rssi & count thresholds */ OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ if (!ar5212SetChannel(ah, chan)) FAIL(HAL_EIO); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); ar5212SetCoverageClass(ah, AH_PRIVATE(ah)->ah_coverageClass, 1); ar5212SetRateDurationTable(ah, chan); /* Set Tx frame start to tx data start delay */ if (IS_RAD5112_ANY(ah) && (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { txFrm2TxDStart = IEEE80211_IS_CHAN_HALF(chan) ? TX_FRAME_D_START_HALF_RATE: TX_FRAME_D_START_QUARTER_RATE; OS_REG_RMW_FIELD(ah, AR_PHY_TX_CTL, AR_PHY_TX_FRAME_TO_TX_DATA_START, txFrm2TxDStart); } /* * Setup fast diversity. * Fast diversity can be enabled or disabled via regadd.txt. * Default is enabled. * For reference, * Disable: reg val * 0x00009860 0x00009d18 (if 11a / 11g, else no change) * 0x00009970 0x192bb514 * 0x0000a208 0xd03e4648 * * Enable: 0x00009860 0x00009d10 (if 11a / 11g, else no change) * 0x00009970 0x192fb514 * 0x0000a208 0xd03e6788 */ /* XXX Setup pre PHY ENABLE EAR additions */ /* flush SCAL reg */ if (IS_5312_2_X(ah)) { (void) OS_REG_READ(ah, AR_PHY_SLEEP_SCAL); } /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synthDelay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_B(chan)) { synthDelay = (4 * synthDelay) / 22; } else { synthDelay /= 10; } /* Activate the PHY (includes baseband activate and synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear false triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ if (IEEE80211_IS_CHAN_HALF(chan)) { OS_DELAY((synthDelay << 1) + BASE_ACTIVATE_DELAY); } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { OS_DELAY((synthDelay << 2) + BASE_ACTIVATE_DELAY); } else { OS_DELAY(synthDelay + BASE_ACTIVATE_DELAY); } /* * The udelay method is not reliable with notebooks. * Need to check to see if the baseband is ready */ testReg = OS_REG_READ(ah, AR_PHY_TESTCTRL); /* Selects the Tx hold */ OS_REG_WRITE(ah, AR_PHY_TESTCTRL, AR_PHY_TESTCTRL_TXHOLD); i = 0; while ((i++ < 20) && (OS_REG_READ(ah, 0x9c24) & 0x10)) /* test if baseband not ready */ OS_DELAY(200); OS_REG_WRITE(ah, AR_PHY_TESTCTRL, testReg); /* Calibrate the AGC and start a NF calculation */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL | AR_PHY_AGC_CONTROL_NF); if (!IEEE80211_IS_CHAN_B(chan) && ahp->ah_bIQCalibration != IQ_CAL_DONE) { /* Start IQ calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, INIT_IQCAL_LOG_COUNT_MAX); OS_REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4, AR_PHY_TIMING_CTRL4_DO_IQCAL); ahp->ah_bIQCalibration = IQ_CAL_RUNNING; } else ahp->ah_bIQCalibration = IQ_CAL_INACTIVE; /* Setup compression registers */ ar5212SetCompRegs(ah); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); ahp->ah_intrTxqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) ar5212ResetTxQueue(ah, i); /* * Setup interrupt handling. Note that ar5212ResetTxQueue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_maskReg = AR_IMR_TXOK | AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXOK | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_HIUERR ; if (opmode == HAL_M_HOSTAP) ahp->ah_maskReg |= AR_IMR_MIB; OS_REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); /* Enable bus errors that are OR'd to set the HIUERR bit */ OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_MCABT | AR_IMR_S2_SSERR | AR_IMR_S2_DPERR); if (AH_PRIVATE(ah)->ah_rfkillEnabled) ar5212EnableRfKill(ah); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset calibration failed to complete in 1ms;" " noisy environment?\n", __func__); } /* * Set clocks back to 32kHz if they had been using refClk, then * use an external 32kHz crystal when sleeping, if one exists. */ ar5312SetupClock(ah, opmode); /* * Writing to AR_BEACON will start timers. Hence it should * be the last register to be written. Do not reset tsf, do * not enable beacons at this point, but preserve other values * like beaconInterval. */ OS_REG_WRITE(ah, AR_BEACON, (OS_REG_READ(ah, AR_BEACON) &~ (AR_BEACON_EN | AR_BEACON_RESET_TSF))); /* XXX Setup post reset EAR additions */ /* QoS support */ if (AH_PRIVATE(ah)->ah_macVersion > AR_SREV_VERSION_VENICE || (AH_PRIVATE(ah)->ah_macVersion == AR_SREV_VERSION_VENICE && AH_PRIVATE(ah)->ah_macRev >= AR_SREV_GRIFFIN_LITE)) { OS_REG_WRITE(ah, AR_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_QOS_SELECT, 0x3210); /* XXX magic */ } /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_NOACK, SM(2, AR_NOACK_2BIT_VALUE) | SM(5, AR_NOACK_BIT_OFFSET) | SM(0, AR_NOACK_BYTE_OFFSET)); /* Restore user-specified settings */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); if (ahp->ah_slottime != (u_int) -1) ar5212SetSlotTime(ah, ahp->ah_slottime); if (ahp->ah_acktimeout != (u_int) -1) ar5212SetAckTimeout(ah, ahp->ah_acktimeout); if (ahp->ah_ctstimeout != (u_int) -1) ar5212SetCTSTimeout(ah, ahp->ah_ctstimeout); if (ahp->ah_sifstime != (u_int) -1) ar5212SetSifsTime(ah, ahp->ah_sifstime); if (AH_PRIVATE(ah)->ah_diagreg != 0) OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ if (bChannelChange && !IEEE80211_IS_CHAN_DFS(chan)) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n", __func__); OS_MARK(ah, AH_MARK_RESET_DONE, 0); return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); if (status != AH_NULL) *status = ecode; return AH_FALSE; #undef FAIL #undef N }
/* * Process a radar event. * * If a radar event is found, return 1. Otherwise, return 0. * * There is currently no way to specify that a radar event has occured on * a specific channel, so the current methodology is to mark both the pri * and ext channels as being unavailable. This should be fixed for 802.11ac * or we'll quickly run out of valid channels to use. */ int dfs_process_radarevent(struct ath_dfs *dfs, struct ieee80211_channel *chan) { struct dfs_event re,*event; struct dfs_state *rs=NULL; struct dfs_filtertype *ft; struct dfs_filter *rf; int found, retval = 0, p, empty; int events_processed = 0; u_int32_t tabledepth, index; u_int64_t deltafull_ts = 0, this_ts, deltaT; struct ieee80211_channel *thischan; struct dfs_pulseline *pl; static u_int32_t test_ts = 0; static u_int32_t diff_ts = 0; int ext_chan_event_flag = 0; int i; if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_sfs is NULL\n", __func__); return 0; } pl = dfs->pulses; if ( !(IEEE80211_IS_CHAN_DFS(dfs->ic->ic_curchan))) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s: radar event on non-DFS chan\n", __func__); dfs_reset_radarq(dfs); dfs_reset_alldelaylines(dfs); return 0; } #ifndef ATH_DFS_RADAR_DETECTION_ONLY /* TEST : Simulate radar bang, make sure we add the channel to NOL (bug 29968) */ if (dfs->dfs_bangradar) { /* bangradar will always simulate radar found on the primary channel */ rs = &dfs->dfs_radar[dfs->dfs_curchan_radindex]; dfs->dfs_bangradar = 0; /* reset */ DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: bangradar\n", __func__); retval = 1; goto dfsfound; } #endif /* The HW may miss some pulses especially with high channel loading. This is true for Japan W53 where channel loaoding is 50%. Also for ETSI where channel loading is 30% this can be an issue too. To take care of missing pulses, we introduce pri_margin multiplie. This is normally 2 but can be higher for W53. */ if ((dfs->dfsdomain == DFS_MKK4_DOMAIN) && (dfs->dfs_caps.ath_chip_is_bb_tlv) && (chan->ic_freq < FREQ_5500_MHZ)) { dfs->dfs_pri_multiplier = DFS_W53_DEFAULT_PRI_MULTIPLIER; /* do not process W53 pulses unless we have a minimum number of them */ if (dfs->dfs_phyerr_w53_counter >= 5) { /* for chips that support frequency information, we can relax PRI restriction if the frequency spread is narrow. */ if ((dfs->dfs_phyerr_freq_max - dfs->dfs_phyerr_freq_min) < DFS_MAX_FREQ_SPREAD) { dfs->dfs_pri_multiplier = DFS_LARGE_PRI_MULTIPLIER; } DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: w53_counter=%d, freq_max=%d, freq_min=%d, pri_multiplier=%d\n", __func__, dfs->dfs_phyerr_w53_counter, dfs->dfs_phyerr_freq_max, dfs->dfs_phyerr_freq_min, dfs->dfs_pri_multiplier); dfs->dfs_phyerr_freq_min = 0x7fffffff; dfs->dfs_phyerr_freq_max = 0; } else { return 0; } } DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: pri_multiplier=%d\n", __func__, dfs->dfs_pri_multiplier); ATH_DFSQ_LOCK(dfs); empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); ATH_DFSQ_UNLOCK(dfs); while ((!empty) && (!retval) && (events_processed < MAX_EVENTS)) { ATH_DFSQ_LOCK(dfs); event = STAILQ_FIRST(&(dfs->dfs_radarq)); if (event != NULL) STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); ATH_DFSQ_UNLOCK(dfs); if (event == NULL) { empty = 1; break; } events_processed++; re = *event; OS_MEMZERO(event, sizeof(struct dfs_event)); ATH_DFSEVENTQ_LOCK(dfs); STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); ATH_DFSEVENTQ_UNLOCK(dfs); found = 0; if (re.re_chanindex < DFS_NUM_RADAR_STATES) rs = &dfs->dfs_radar[re.re_chanindex]; else { ATH_DFSQ_LOCK(dfs); empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); ATH_DFSQ_UNLOCK(dfs); continue; } if (rs->rs_chan.ic_flagext & CHANNEL_INTERFERENCE) { ATH_DFSQ_LOCK(dfs); empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); ATH_DFSQ_UNLOCK(dfs); continue; } if (dfs->dfs_rinfo.rn_lastfull_ts == 0) { /* * Either not started, or 64-bit rollover exactly to zero * Just prepend zeros to the 15-bit ts */ dfs->dfs_rinfo.rn_ts_prefix = 0; } else { /* WAR 23031- patch duplicate ts on very short pulses */ /* This pacth has two problems in linux environment. * 1)The time stamp created and hence PRI depends entirely on the latency. * If the latency is high, it possibly can split two consecutive * pulses in the same burst so far away (the same amount of latency) * that make them look like they are from differenct bursts. It is * observed to happen too often. It sure makes the detection fail. * 2)Even if the latency is not that bad, it simply shifts the duplicate * timestamps to a new duplicate timestamp based on how they are processed. * This is not worse but not good either. * * Take this pulse as a good one and create a probable PRI later */ if (re.re_dur == 0 && re.re_ts == dfs->dfs_rinfo.rn_last_unique_ts) { debug_dup[debug_dup_cnt++] = '1'; DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "\n %s deltaT is 0 \n", __func__); } else { dfs->dfs_rinfo.rn_last_unique_ts = re.re_ts; debug_dup[debug_dup_cnt++] = '0'; } if (debug_dup_cnt >= 32) { debug_dup_cnt = 0; } if (re.re_ts <= dfs->dfs_rinfo.rn_last_ts) { dfs->dfs_rinfo.rn_ts_prefix += (((u_int64_t) 1) << DFS_TSSHIFT); /* Now, see if it's been more than 1 wrap */ deltafull_ts = re.re_full_ts - dfs->dfs_rinfo.rn_lastfull_ts; if (deltafull_ts > ((u_int64_t)((DFS_TSMASK - dfs->dfs_rinfo.rn_last_ts) + 1 + re.re_ts))) deltafull_ts -= (DFS_TSMASK - dfs->dfs_rinfo.rn_last_ts) + 1 + re.re_ts; deltafull_ts = deltafull_ts >> DFS_TSSHIFT; if (deltafull_ts > 1) { dfs->dfs_rinfo.rn_ts_prefix += ((deltafull_ts - 1) << DFS_TSSHIFT); } } else { deltafull_ts = re.re_full_ts - dfs->dfs_rinfo.rn_lastfull_ts; if (deltafull_ts > (u_int64_t) DFS_TSMASK) { deltafull_ts = deltafull_ts >> DFS_TSSHIFT; dfs->dfs_rinfo.rn_ts_prefix += ((deltafull_ts - 1) << DFS_TSSHIFT); } }
/* * 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; }
/* * Find the channel information according to the scan entry */ int rtt_find_channel_info (void *arg, wlan_scan_entry_t scan_entry) { wmi_channel *wmi_chan; u_int32_t chan_mode; struct ieee80211com *ic; struct ieee80211_channel *se_chan; static const u_int modeflags[] = { 0, /* IEEE80211_MODE_AUTO */ MODE_11A, /* IEEE80211_MODE_11A */ MODE_11B, /* IEEE80211_MODE_11B */ MODE_11G, /* IEEE80211_MODE_11G */ 0, /* IEEE80211_MODE_FH */ 0, /* IEEE80211_MODE_TURBO_A */ 0, /* IEEE80211_MODE_TURBO_G */ MODE_11NA_HT20, /* IEEE80211_MODE_11NA_HT20 */ MODE_11NG_HT20, /* IEEE80211_MODE_11NG_HT20 */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40PLUS */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40MINUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40PLUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40MINUS */ MODE_11NG_HT40, /* IEEE80211_MODE_11NG_HT40 */ MODE_11NA_HT40, /* IEEE80211_MODE_11NA_HT40 */ MODE_11AC_VHT20, /* IEEE80211_MODE_11AC_VHT20 */ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40PLUS */ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40MINUS*/ MODE_11AC_VHT40, /* IEEE80211_MODE_11AC_VHT40 */ MODE_11AC_VHT80, /* IEEE80211_MODE_11AC_VHT80 */ }; adf_os_print("%s:\n", __func__); if (!(arg && scan_entry)) { return -1; //critical error } wmi_chan = ((channel_search *)arg)->channel; ic = ((channel_search *)arg)->ic; if(!(wmi_chan && ic)) { return -1; //critical error } se_chan = wlan_scan_entry_channel(scan_entry); if(!se_chan) { return -1; //critical error } wmi_chan->mhz = ieee80211_chan2freq(ic,se_chan); chan_mode = ieee80211_chan2mode(se_chan); WMI_SET_CHANNEL_MODE(wmi_chan, modeflags[chan_mode]); if(chan_mode == IEEE80211_MODE_11AC_VHT80) { if (se_chan->ic_ieee < 20) { wmi_chan->band_center_freq1 = ieee80211_ieee2mhz( se_chan->ic_vhtop_ch_freq_seg1, IEEE80211_CHAN_2GHZ); } else { wmi_chan->band_center_freq1 = ieee80211_ieee2mhz( se_chan->ic_vhtop_ch_freq_seg1, IEEE80211_CHAN_5GHZ); } } else if((chan_mode == IEEE80211_MODE_11NA_HT40PLUS) || (chan_mode == IEEE80211_MODE_11NG_HT40PLUS) || (chan_mode == IEEE80211_MODE_11AC_VHT40PLUS)) { wmi_chan->band_center_freq1 = wmi_chan->mhz + 10; } else if((chan_mode == IEEE80211_MODE_11NA_HT40MINUS) || (chan_mode == IEEE80211_MODE_11NG_HT40MINUS) || (chan_mode == IEEE80211_MODE_11AC_VHT40MINUS)) { wmi_chan->band_center_freq1 = wmi_chan->mhz - 10; } else { wmi_chan->band_center_freq1 = wmi_chan->mhz; } /* we do not support HT80PLUS80 yet */ wmi_chan->band_center_freq2=0; WMI_SET_CHANNEL_MIN_POWER(wmi_chan, se_chan->ic_minpower); WMI_SET_CHANNEL_MAX_POWER(wmi_chan, se_chan->ic_maxpower); WMI_SET_CHANNEL_REG_POWER(wmi_chan, se_chan->ic_maxregpower); WMI_SET_CHANNEL_ANTENNA_MAX(wmi_chan, se_chan->ic_antennamax); WMI_SET_CHANNEL_REG_CLASSID(wmi_chan, se_chan->ic_regClassId); if (IEEE80211_IS_CHAN_DFS(se_chan)) WMI_SET_CHANNEL_FLAG(wmi_chan, WMI_CHAN_FLAG_DFS); adf_os_print("WMI channel freq=%d, mode=%x band_center_freq1=%d\n", wmi_chan->mhz, WMI_GET_CHANNEL_MODE(wmi_chan), wmi_chan->band_center_freq1); return 1; //seccessful! }
static int ol_vdev_wmi_event_handler(ol_scn_t scn, u_int8_t *data, u_int16_t datalen, void *context) { ieee80211_resmgr_t resmgr = (ieee80211_resmgr_t )context; wmi_vdev_start_response_event *wmi_vdev_start_resp_ev = (wmi_vdev_start_response_event *)data; wlan_if_t vaphandle; struct ieee80211com *ic = resmgr->ic; struct ieee80211_channel *chan = NULL; struct ieee80211_node *ni; u_int8_t numvaps, actidx = 0; struct ol_ath_vap_net80211 *avn; bool do_notify = true; vaphandle = ol_ath_vap_get(scn, wmi_vdev_start_resp_ev->vdev_id); if (NULL == vaphandle) { printk("Event received for Invalid/Deleted vap handle\n"); return 0; } avn = OL_ATH_VAP_NET80211(vaphandle); printk("ol_vdev_start_resp_ev for vap %d (%p)\n", wmi_vdev_start_resp_ev->vdev_id, scn->wmi_handle); spin_lock(&vaphandle->init_lock); switch (vaphandle->iv_opmode) { case IEEE80211_M_MONITOR: /* Handle same as HOSTAP */ case IEEE80211_M_HOSTAP: /* If vap is not waiting for the WMI event from target return here */ if(avn->av_ol_resmgr_wait == FALSE) { spin_unlock(&vaphandle->init_lock); return 0; } /* Resetting the ol_resmgr_wait flag*/ avn->av_ol_resmgr_wait = FALSE; numvaps = ieee80211_vaps_active(ic); chan = vaphandle->iv_des_chan[vaphandle->iv_des_mode]; /* * if there is a vap already running. * ignore the desired channel and use the * operating channel of the other vap. */ /* so that cwm can do its own crap. need to untie from state */ /* vap join is called here to wake up the chip if it is in sleep state */ ieee80211_vap_join(vaphandle); if (numvaps == 0) { //AP_DFS: ieee80211_set_channel(ic, chan); if (wmi_vdev_start_resp_ev->resp_type != WMI_VDEV_RESTART_RESP_EVENT) { /* 20/40 Mhz coexistence handler */ if ((avn->av_ol_resmgr_chan != NULL) && (chan != avn->av_ol_resmgr_chan)) { chan = avn->av_ol_resmgr_chan; } ic->ic_prevchan = ic->ic_curchan; ic->ic_curchan = chan; /*update channel history*/ actidx = ic->ic_chanidx; ic->ic_chanhist[actidx].chanid = (ic->ic_curchan)->ic_ieee; ic->ic_chanhist[actidx].chanjiffies = OS_GET_TIMESTAMP(); ic->ic_chanidx == (IEEE80211_CHAN_MAXHIST - 1) ? ic->ic_chanidx = 0 : ++(ic->ic_chanidx); /* update max channel power to max regpower of current channel */ ieee80211com_set_curchanmaxpwr(ic, chan->ic_maxregpower); ieee80211_wme_initparams(vaphandle); } /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; /* XXX reset erp state */ ieee80211_reset_erp(ic, ic->ic_curmode, vaphandle->iv_opmode); } else { /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; } /* use the vap bsschan for dfs configure */ if ( IEEE80211_IS_CHAN_DFS(vaphandle->iv_bsschan)) { extern void ol_if_dfs_configure(struct ieee80211com *ic); ol_if_dfs_configure(ic); } break; case IEEE80211_M_STA: ni = vaphandle->iv_bss; chan = ni->ni_chan; vaphandle->iv_bsschan = chan; ic->ic_prevchan = ic->ic_curchan; ic->ic_curchan = chan; /* update max channel power to max regpower of current channel */ ieee80211com_set_curchanmaxpwr(ic, chan->ic_maxregpower); /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; /* XXX reset erp state */ ieee80211_reset_erp(ic, ic->ic_curmode, vaphandle->iv_opmode); ieee80211_wme_initparams(vaphandle); if (wmi_vdev_start_resp_ev->resp_type == WMI_VDEV_RESTART_RESP_EVENT) { do_notify = false; } break; default: break; } vaphandle->init_in_progress = false; spin_unlock(&vaphandle->init_lock); /* Intimate start completion to VAP module */ /* if STA, bypass notification for RESTERT EVENT */ if (do_notify) ieee80211_notify_vap_start_complete(resmgr, vaphandle, IEEE80211_RESMGR_STATUS_SUCCESS); 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 is_ext_ch; int is_fastclk = 0; int radar_filters_init_status = 0; //u_int32_t rfilt; struct ath_dfs *dfs; struct dfs_state *rs_pri, *rs_ext; struct ieee80211_channel *chan=ic->ic_curchan, *ext_ch = NULL; is_ext_ch=IEEE80211_IS_CHAN_11N_HT40(ic->ic_curchan); dfs=(struct ath_dfs *)ic->ic_dfs; rs_pri = NULL; rs_ext = NULL; #if 0 int i; #endif if (dfs == NULL) { DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: ic_dfs is NULL\n", __func__); return -EIO; } ic->ic_dfs_disable(ic); /* * Setting country code might change the DFS domain * so initialize the DFS Radar filters */ radar_filters_init_status = dfs_init_radar_filters(ic, radar_info); /* * dfs_init_radar_filters() returns 1 on failure and * 0 on success. */ if ( DFS_STATUS_FAIL == radar_filters_init_status ) { VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR, "%s[%d]: DFS Radar Filters Initialization Failed", __func__, __LINE__); return -EIO; } if ((ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS)) { if (IEEE80211_IS_CHAN_DFS(chan)) { 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; 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; dfs->dfs_pri_multiplier_ini = radar_info->dfs_pri_multiplier; 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 ); 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 DFS_STATUS_SUCCESS; }