Author: adrian
Date: Mon Oct  3 12:12:03 2011
New Revision: 225934
URL: http://svn.freebsd.org/changeset/base/225934

Log:
  Port over the radar pulse decoding code common to the AR5416 and later 
chipsets.
  
  Obtained from:        Atheros

Modified:
  head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c

Modified: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
==============================================================================
--- head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c       Mon Oct  3 10:23:28 
2011        (r225933)
+++ head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c       Mon Oct  3 12:12:03 
2011        (r225934)
@@ -21,9 +21,7 @@
 #include "ah.h"
 #include "ah_internal.h"
 #include "ah_devid.h"
-#ifdef AH_DEBUG
 #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
-#endif
 
 #include "ar5416/ar5416.h"
 #include "ar5416/ar5416reg.h"
@@ -757,14 +755,200 @@ ar5416EnableDfs(struct ath_hal *ah, HAL_
  * Returns AH_TRUE if the phy error was actually a phy error,
  * AH_FALSE if the phy error wasn't a phy error.
  */
+
+/* Flags for pulse_bw_info */
+#define        PRI_CH_RADAR_FOUND              0x01
+#define        EXT_CH_RADAR_FOUND              0x02
+#define        EXT_CH_RADAR_EARLY_FOUND        0x04
+
 HAL_BOOL
 ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
     uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
 {
+       HAL_BOOL doDfsExtCh;
+       HAL_BOOL doDfsEnhanced;
+       HAL_BOOL doDfsCombinedRssi;
+
+       uint8_t rssi = 0, ext_rssi = 0;
+       uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
+       uint32_t dur = 0;
+       int pri_found = 1, ext_found = 0;
+       int early_ext = 0;
+       int is_dc = 0;
+       uint16_t datalen;               /* length from the RX status field */
+
+       /* Check whether the given phy error is a radar event */
+       if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
+           (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
+               return AH_FALSE;
+       }
+
+       /* Grab copies of the capabilities; just to make the code clearer */
+       doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
+       doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
+       doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
+
+       datalen = rxs->rs_datalen;
+
+       /* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
+       if (doDfsCombinedRssi)
+               rssi = (uint8_t) rxs->rs_rssi;
+       else            
+               rssi = (uint8_t) rxs->rs_rssi_ctl[0];
+
+       /* Set this; but only use it if doDfsExtCh is set */
+       ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
+
+       /* Cap it at 0 if the RSSI is a negative number */
+       if (rssi & 0x80)
+               rssi = 0;
+
+       if (ext_rssi & 0x80)
+               ext_rssi = 0;
+
+       /*
+        * Fetch the relevant data from the frame
+        */
+       if (doDfsExtCh) {
+               if (datalen < 3)
+                       return AH_FALSE;
+
+               /* Last three bytes of the frame are of interest */
+               pulse_length_pri = *(buf + datalen - 3);
+               pulse_length_ext = *(buf + datalen - 2);
+               pulse_bw_info = *(buf + datalen - 1);
+               HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, 
pulse_length_pri=%d,"
+                   " pulse_length_ext=%d, pulse_bw_info=%x\n",
+                   __func__, rssi, ext_rssi, pulse_length_pri, 
pulse_length_ext,
+                   pulse_bw_info);
+       } else {
+               /* The pulse width is byte 0 of the data */
+               if (datalen >= 1)
+                       dur = ((uint8_t) buf[0]) & 0xff;
+               else
+                       dur = 0;
+
+               if (dur == 0 && rssi == 0) {
+                       HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", 
__func__);
+                       return AH_FALSE;
+               }
+
+               HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, 
rssi, dur);
+
+               /* Single-channel only */
+               pri_found = 1;
+               ext_found = 0;
+       }
+
+       /*
+        * If doing extended channel data, pulse_bw_info must
+        * have one of the flags set.
+        */
+       if (doDfsExtCh && pulse_bw_info == 0x0)
+               return AH_FALSE;
+               
        /*
-        * For now, this isn't implemented.
+        * If the extended channel data is available, calculate
+        * which to pay attention to.
         */
-       return AH_FALSE;
+       if (doDfsExtCh) {
+               /* If pulse is on DC, take the larger duration of the two */
+               if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
+                   (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
+                       is_dc = 1;
+                       if (pulse_length_ext > pulse_length_pri) {
+                               dur = pulse_length_ext;
+                               pri_found = 0;
+                               ext_found = 1;
+                       } else {
+                               dur = pulse_length_pri;
+                               pri_found = 1;
+                               ext_found = 0;
+                       }
+               } else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
+                       dur = pulse_length_ext;
+                       pri_found = 0;
+                       ext_found = 1;
+                       early_ext = 1;
+               } else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
+                       dur = pulse_length_pri;
+                       pri_found = 1;
+                       ext_found = 0;
+               } else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
+                       dur = pulse_length_ext;
+                       pri_found = 0;
+                       ext_found = 1;
+               }
+               
+       }
+
+       /*
+        * For enhanced DFS (Merlin and later), pulse_bw_info has
+        * implications for selecting the correct RSSI value.
+        */
+       if (doDfsEnhanced) {
+               switch (pulse_bw_info & 0x03) {
+               case 0:
+                       /* No radar? */
+                       rssi = 0;
+                       break;
+               case PRI_CH_RADAR_FOUND:
+                       /* Radar in primary channel */
+                       /* Cannot use ctrl channel RSSI if ext channel is 
stronger */
+                       if (ext_rssi >= (rssi + 3)) {
+                               rssi = 0;
+                       };
+                       break;
+               case EXT_CH_RADAR_FOUND:
+                       /* Radar in extended channel */
+                       /* Cannot use ext channel RSSI if ctrl channel is 
stronger */
+                       if (rssi >= (ext_rssi + 12)) {
+                               rssi = 0;
+                       } else {
+                               rssi = ext_rssi;
+                       }
+                       break;
+               case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
+                       /* When both are present, use stronger one */
+                       if (rssi < ext_rssi)
+                               rssi = ext_rssi;
+                       break;
+               }
+       }
+
+       /*
+        * If not doing enhanced DFS, choose the ext channel if
+        * it is stronger than the main channel
+        */
+       if (doDfsExtCh && !doDfsEnhanced) {
+               if ((ext_rssi > rssi) && (ext_rssi < 128))
+                       rssi = ext_rssi;
+       }
+
+       /*
+        * XXX what happens if the above code decides the RSSI
+        * XXX wasn't valid, an sets it to 0?
+        */
+
+       /*
+        * Fill out dfs_event structure.
+        */
+       event->re_full_ts = fulltsf;
+       event->re_ts = rxs->rs_tstamp;
+       event->re_rssi = rssi;
+       event->re_dur = dur;
+
+       event->re_flags = 0;
+       if (pri_found)
+               event->re_flags |= HAL_DFS_EVENT_PRICH;
+       if (ext_found)
+               event->re_flags |= HAL_DFS_EVENT_EXTCH;
+       if (early_ext)
+               event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
+       if (is_dc)
+               event->re_flags |= HAL_DFS_EVENT_ISDC;
+
+       return AH_TRUE;
 }
 
 /*
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to