示例#1
0
void
dfs_reset_radarq(struct ath_dfs *dfs)
{
   struct dfs_event *event;
   if (dfs == NULL) {
      DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL", __func__);
      return;
   }
   ATH_DFSQ_LOCK(dfs);
   ATH_DFSEVENTQ_LOCK(dfs);
   while (!STAILQ_EMPTY(&(dfs->dfs_radarq))) {
      event = STAILQ_FIRST(&(dfs->dfs_radarq));
      STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list);
      OS_MEMZERO(event, sizeof(struct dfs_event));
      STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list);
   }
   ATH_DFSEVENTQ_UNLOCK(dfs);
   ATH_DFSQ_UNLOCK(dfs);
}
示例#2
0
int
dfs_process_radarevent(struct ath_softc *sc, HAL_CHANNEL *chan)
{
	struct ath_dfs *dfs=sc->sc_dfs;
	struct ath_hal *ah=sc->sc_ah;
	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, rfilt, index;
	u_int64_t deltafull_ts = 0, this_ts, deltaT;
	HAL_CHANNEL *thischan;
	HAL_PHYERR_PARAM pe;
    struct dfs_pulseline *pl;
    static u_int32_t  test_ts  = 0;
    static u_int32_t  diff_ts  = 0;
    int ext_chan_event_flag = 0;

	if (dfs == NULL) {
		DFS_DPRINTK(sc, ATH_DEBUG_DFS, "%s: sc_sfs is NULL\n",
			__func__);
		return 0;
	}
    pl = dfs->pulses;
	if ( ! (sc->sc_curchan.priv_flags & CHANNEL_DFS)) {
	        DFS_DPRINTK(sc, ATH_DEBUG_DFS2, "%s: radar event on non-DFS chan\n",
                        __func__);
                dfs_reset_radarq(sc);
                dfs_reset_alldelaylines(sc);
        	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(sc, ATH_DEBUG_DFS, "%s: bangradar\n", __func__);
 		     retval = 1;                    
                     goto dfsfound;
 	 }
#endif


	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.priv_flags & 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;
			this_ts = (u_int64_t) re.re_ts;
		} 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(sc, 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);
				}
			}
示例#3
0
/*
 * 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);
                }
            }
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
}
示例#5
0
void
ath_process_phyerr(struct ath_softc *sc, struct ath_buf *bf, struct ath_rx_status *rxs, u_int64_t fulltsf)
{
#define EXT_CH_RADAR_FOUND 0x02
#define PRI_CH_RADAR_FOUND 0x01
#define EXT_CH_RADAR_EARLY_FOUND 0x04
        struct ath_dfs *dfs=sc->sc_dfs;
	HAL_CHANNEL *chan=&sc->sc_curchan;
	struct dfs_event *event;
	u_int8_t rssi;
	u_int8_t ext_rssi=0;
        u_int8_t pulse_bw_info=0, pulse_length_ext=0, pulse_length_pri=0;
	u_int32_t dur=0;
        u_int16_t datalen;
        int pri_found=1, ext_found=0, dc_found=0, early_ext=0, slope=0, add_dur=0;

	int empty;
        u_int32_t *last_word_ptr, *secondlast_word_ptr;
        u_int8_t *byte_ptr, last_byte_0, last_byte_1, last_byte_2, last_byte_3; 
        u_int8_t secondlast_byte_0, secondlast_byte_1, secondlast_byte_2, secondlast_byte_3; 

	if (((rxs->rs_phyerr != HAL_PHYERR_RADAR)) &&
	    ((rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)))  {
		DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "%s: rs_phyer=0x%x not a radar error\n",__func__, rxs->rs_phyerr);
        	return;
        }

        /* 
           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 (chan->priv_flags & CHANNEL_INTERFERENCE) {
                DFS_DPRINTK(sc, ATH_DEBUG_DFS1, "%s: Radar already found in the channel, do not queue radar data\n", __func__);
                return;
        } 

	if (dfs == NULL) {
		DFS_DPRINTK(sc, ATH_DEBUG_DFS, "%s: sc_dfs is NULL\n",__func__);
		return;
	}
        dfs->ath_dfs_stats.total_phy_errors++;
        datalen = rxs->rs_datalen;
        /* WAR: Never trust combined RSSI on radar pulses for <=
         * OWL2.0. For short pulses only the chain 0 rssi is present
         * and remaining descriptor data is all 0x80, for longer
         * pulses the descriptor is present, but the combined value is
         * inaccurate. This HW capability is queried in dfs_attach and stored in
         * the sc_dfs_combined_rssi_ok flag.*/

        if (sc->sc_dfs->sc_dfs_combined_rssi_ok) {
                rssi = (u_int8_t) rxs->rs_rssi;
        } else {
            rssi = (u_int8_t) rxs->rs_rssi_ctl0;
        }

        ext_rssi = (u_int8_t) rxs->rs_rssi_ext0;


        /* hardware stores this as 8 bit signed value.
         * we will cap it at 0 if it is a negative number 
         */

        if (rssi & 0x80)
            rssi = 0;

        if (ext_rssi & 0x80)
            ext_rssi = 0;

        last_word_ptr = (u_int32_t *)(((u_int8_t*)bf->bf_vdata) + datalen - (datalen%4));


        secondlast_word_ptr = last_word_ptr-1;

        byte_ptr = (u_int8_t*)last_word_ptr; 
        last_byte_0=(*(byte_ptr) & 0xff); 
        last_byte_1=(*(byte_ptr+1) & 0xff); 
        last_byte_2=(*(byte_ptr+2) & 0xff); 
        last_byte_3=(*(byte_ptr+3) & 0xff); 

        byte_ptr = (u_int8_t*)secondlast_word_ptr; 
        secondlast_byte_0=(*(byte_ptr) & 0xff); 
        secondlast_byte_1=(*(byte_ptr+1) & 0xff); 
        secondlast_byte_2=(*(byte_ptr+2) & 0xff); 
        secondlast_byte_3=(*(byte_ptr+3) & 0xff); 
       
        /* If radar can be detected on the extension channel (for SOWL onwards), we have to read radar data differently as the HW supplies bwinfo and duration for both primary and extension channel.*/
        if (sc->sc_dfs->sc_dfs_ext_chan_ok) {
        
        /* If radar can be detected on the extension channel, datalen zero pulses are bogus, discard them.*/
        if (!datalen) {
            dfs->ath_dfs_stats.datalen_discards++;
            return;
        }
        switch((datalen & 0x3)) {
        case 0:
            pulse_bw_info = secondlast_byte_3;
            pulse_length_ext = secondlast_byte_2;
            pulse_length_pri = secondlast_byte_1;
            break;
        case 1:
            pulse_bw_info = last_byte_0;
            pulse_length_ext = secondlast_byte_3;
            pulse_length_pri = secondlast_byte_2;
            break;
        case 2:
            pulse_bw_info = last_byte_1;
            pulse_length_ext = last_byte_0;
            pulse_length_pri = secondlast_byte_3;
           break;
        case 3:
            pulse_bw_info = last_byte_2;
            pulse_length_ext = last_byte_1;
            pulse_length_pri = last_byte_0;
            break;
        default:
            DFS_DPRINTK(sc, ATH_DEBUG_DFS, "datalen mod4=%d\n", (datalen%4));
        }

        /* Only the last 3 bits of the BW info are relevant, they indicate
        which channel the radar was detected in.*/
        pulse_bw_info &= 0x07;
        /* If pulse on DC, both primary and extension flags will be set */
        if (((pulse_bw_info & EXT_CH_RADAR_FOUND) && (pulse_bw_info & PRI_CH_RADAR_FOUND))) {

            /* Conducted testing, when pulse is on DC, both pri and ext durations are reported to be same
               Radiated testing, when pulse is on DC, different pri and ext durations are reported, so take the larger of the two */
            if (pulse_length_ext >= pulse_length_pri) {
                dur = pulse_length_ext;
                ext_found = 1;
            } else {
                dur = pulse_length_pri;
                pri_found = 1;
            }
            dfs->ath_dfs_stats.dc_phy_errors++;         

        } else {
        if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
            dur = pulse_length_ext;
            pri_found = 0;
            ext_found = 1;
            dfs->ath_dfs_stats.ext_phy_errors++;         
        } 
        if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
            dur = pulse_length_pri;
            pri_found = 1;
            ext_found = 0;
            dfs->ath_dfs_stats.pri_phy_errors++;         
        } 
        if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
             dur = pulse_length_ext;
             pri_found = 0;
             ext_found = 1; early_ext = 1;
             dfs->ath_dfs_stats.early_ext_phy_errors++;         
	     DFS_DPRINTK(sc, ATH_DEBUG_DFS2, "EARLY ext channel dur=%u rssi=%u datalen=%d\n",dur, rssi, datalen);
        } 
        if (!pulse_bw_info) {
	    DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "ERROR channel dur=%u rssi=%u pulse_bw_info=0x%x datalen MOD 4 = %d\n",dur, rssi, pulse_bw_info, (datalen & 0x3));
            /* Bogus bandwidth info received in descriptor, 
            so ignore this PHY error */
            dfs->ath_dfs_stats.bwinfo_errors++;
            return; 
        }
    }

    if (sc->sc_dfs->sc_dfs_use_enhancement) {
        /*
         * for osprey (and Merlin) bw_info has implication for selecting RSSI value
         */

        switch (pulse_bw_info & 0x03) {
        case 0x00:
            /* No radar in ctrl or ext channel */
            rssi = 0;
            break;
        case 0x01:
            /* radar in ctrl channel */
            DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi);
            if (ext_rssi >= (rssi + 3)) {
                /* cannot use ctrl channel RSSI if extension channel is stronger */
                rssi = 0;
            }
            break;
        case 0x02:
            /* radar in extension channel */
	    
            DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi);
            if (rssi >= (ext_rssi + 12)) {
                /* cannot use extension channel RSSI if control channel is stronger */
                rssi = 0;
            } else {
                rssi = ext_rssi;
            }
            break;
        case 0x03:
           /* when both are present use stronger one */
            if (rssi < ext_rssi) {
                rssi = ext_rssi;
            }
            break;
        } 
    } else {
        /* Always use combined RSSI reported, unless RSSI reported on 
           extension is stronger */
        if ((ext_rssi > rssi) && (ext_rssi < 128)) {
                    rssi = ext_rssi;
        }
    }
        DFS_DPRINTK(sc, ATH_DEBUG_DFS1, "pulse_bw_info=0x%x pulse_length_ext=%u pulse_length_pri=%u rssi=%u ext_rssi=%u phyerr=0x%x\n", pulse_bw_info, pulse_length_ext, pulse_length_pri, rssi, ext_rssi, rxs->rs_phyerr);

        /* 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)) && 
            (dur >= MAYBE_BIN5_DUR) && (dur < MAX_BIN5_DUR)) {
            add_dur = dfs_check_chirping(sc, bf, rxs, pri_found, ext_found, &slope, &dc_found);
            if (add_dur) {
                DFS_DPRINTK(sc, ATH_DEBUG_DFS2, "old dur %d slope =%d\n", dur, slope);
                    // bump up to a random bin5 pulse duration
                    if (dur < MIN_BIN5_DUR) {
                        dur = dfs_get_random_bin5_dur(sc, fulltsf);
                    }
                DFS_DPRINTK(sc, ATH_DEBUG_DFS2, "new dur %d\n", dur);
            } else {
                dur = MAX_BIN5_DUR + 100;       /* set the duration so that it is rejected */
                DFS_DPRINTK(sc, ATH_DEBUG_DFS2,"is_chirping = %d dur=%d \n", add_dur, 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)) {
                if (dur >= MAX_BIN5_DUR) {
                    dur = MAX_BIN5_DUR + 50;        /* set the duration so that it is rejected */
                }
            }
        }
    } else {
        dfs->ath_dfs_stats.owl_phy_errors++;
     /* HW cannot detect extension channel radar so it only passes us primary channel radar data*/
            dur = (rxs->rs_datalen && bf->bf_vdata != NULL ?
               (u_int32_t)(*((u_int8_t *) bf->bf_vdata)) : 0) & 0xff;

            if ((rssi == 0) && (dur== 0)){
               return;
            }
            pri_found = 1;
            ext_found = 0;
        }

	ATH_DFSEVENTQ_LOCK(dfs);
	empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
	ATH_DFSEVENTQ_UNLOCK(dfs);
	if (empty) {
		return;
        }

	if ((chan->channel_flags & CHANNEL_108G) == CHANNEL_108G) {
	        if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) {
                		DFS_DPRINTK(sc, 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(sc, 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 = rssi;
		event->re_dur = dur;
		event->re_full_ts = fulltsf;
		event->re_ts = (rxs->rs_tstamp) & DFS_TSMASK;
        	event->re_chanindex = dfs->dfs_curchan_radindex;
		ATH_ARQ_LOCK(dfs);
		STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list);
		ATH_ARQ_UNLOCK(dfs);
	}
	else {
		if (chan->priv_flags & CHANNEL_DFS) {
	                if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
                		DFS_DPRINTK(sc, 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*/
                        if (sc->sc_dfs->sc_dfs_ext_chan_ok) {
			    if ((rssi < dfs->dfs_rinfo.rn_minrssithresh && (dur > 4))||
			        dur > (dfs->dfs_rinfo.rn_maxpulsedur) ) {
                                    dfs->ath_dfs_stats.rssi_discards++;
                		    DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "Extension channel pulse is discarded %d, %d, %d, %d\n", 
						dur, dfs->dfs_rinfo.rn_maxpulsedur, rssi, dfs->dfs_rinfo.rn_minrssithresh);
				    return;
                            }
                        } else {

			    if (rssi < dfs->dfs_rinfo.rn_minrssithresh ||
			        dur > dfs->dfs_rinfo.rn_maxpulsedur) {
                                    dfs->ath_dfs_stats.rssi_discards++;
				    return;
                            }
                        }

			ATH_DFSEVENTQ_LOCK(dfs);
			event = STAILQ_FIRST(&(dfs->dfs_eventq));
			if (event == NULL) {
				ATH_DFSEVENTQ_UNLOCK(dfs);
				DFS_DPRINTK(sc, 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_dur = dur;
			event->re_full_ts = fulltsf;
			event->re_ts = (rxs->rs_tstamp) & DFS_TSMASK;
			event->re_rssi = rssi;
                        if (pri_found == 1) {
        		    event->re_chanindex = dfs->dfs_curchan_radindex;
                        } else {
                            if (dfs->dfs_extchan_radindex == -1) { 
                                DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "%s - phyerr on ext channel\n", __func__);
                            }
        		    event->re_chanindex = dfs->dfs_extchan_radindex;
                            DFS_DPRINTK(sc, ATH_DEBUG_DFS3, "%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);
		}
    }
#undef EXT_CH_RADAR_FOUND
#undef PRI_CH_RADAR_FOUND
#undef EXT_CH_RADAR_EARLY_FOUND
}