Move slot-time, CTS/RTS, and ACK timeout calculations into the driver. Corrected...
authormtaylor <mtaylor@0192ed92-7a03-0410-a25b-9323aeb14dbd>
Thu, 10 Apr 2008 03:46:54 +0000 (03:46 +0000)
committermtaylor <mtaylor@0192ed92-7a03-0410-a25b-9323aeb14dbd>
Thu, 10 Apr 2008 03:46:54 +0000 (03:46 +0000)
You can override:
- slottime
- ctstimeout
- acktimeout

acktimeout and ctstimeout will be selected from the first available of:

1) the explicitly specified override value [if present]
2) a value derived from an explicitly specified slottime [if present]
3) the HALs default behavior / standard settings for the PHY mode

Setting the distance is shorthand for updating the slottime, and both cts and ack timeout values based upon the usual equations for air propagation, speed of light, etc..etc..

git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3508 0192ed92-7a03-0410-a25b-9323aeb14dbd

ath/if_ath.c
ath/if_athvar.h
tools/athctrl.c

index afb5fbac6a396e9505880296a5526fa50cc8b66c..09422c99c7fd9e248b105e8d35b36bd4135ab9f0 100644 (file)
@@ -148,6 +148,8 @@ static void ath_key_update_begin(struct ieee80211vap *);
 static void ath_key_update_end(struct ieee80211vap *);
 static void ath_mode_init(struct net_device *);
 static void ath_setslottime(struct ath_softc *);
+static void ath_setctstimeout(struct ath_softc *);
+static void ath_setacktimeout(struct ath_softc *);
 static void ath_updateslot(struct net_device *);
 static int ath_beaconq_setup(struct ath_softc *);
 static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
@@ -4231,10 +4233,61 @@ ath_mode_init(struct net_device *dev)
            rfilt, mfilt[0], mfilt[1]);
 }
 
+static inline int 
+ath_slottime2timeout(struct ath_softc *sc, int slottime)
+{
+       /* HAL seems to use a constant of 8 for OFDM overhead and 18 for 
+        * CCK overhead.
+        *
+        * XXX: Update based on emperical evidence (potentially save 15us per timeout)
+        */
+       if (((sc->sc_curchan.channelFlags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) ||
+           (((sc->sc_curchan.channelFlags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) && 
+                (sc->sc_ic.ic_flags & IEEE80211_F_SHSLOT)))
+       {
+               /* short slot time - 802.11a, and 802.11g turbo in turbo mode with short slot time */
+               return (slottime * 2) + 8;
+       }
+           
+       /* constant for CCK mib processing time */
+       return (slottime * 2) + 18;
+}
+
+#ifndef MAX
+# define MAX(a, b)     (((a) > (b))? (a) : (b))
+#endif
+
+static inline int 
+ath_default_ctsack_timeout(struct ath_softc *sc)
+{
+       struct ath_hal *ah = sc->sc_ah;
+
+       int slottime = sc->sc_slottimeconf;
+       if (slottime <= 0)
+               slottime = ath_hal_getslottime(ah);
+
+       return ath_slottime2timeout(sc, slottime);
+}
+
+static inline int
+ath_getslottime(struct ath_softc *sc) {
+       return ath_hal_getslottime(sc->sc_ah);
+}
+
+static inline int
+ath_getacktimeout(struct ath_softc *sc) {
+       return ath_hal_getacktimeout(sc->sc_ah);
+}
+
+static inline int
+ath_getctstimeout(struct ath_softc *sc) {
+       return ath_hal_getctstimeout(sc->sc_ah);
+}
+
 /*
  * Set the slot time based on the current setting.
  */
-static void
+static inline void
 ath_setslottime(struct ath_softc *sc)
 {
        struct ieee80211com *ic = &sc->sc_ic;
@@ -4242,11 +4295,43 @@ ath_setslottime(struct ath_softc *sc)
 
        if (sc->sc_slottimeconf > 0) /* manual override */
                ath_hal_setslottime(ah, sc->sc_slottimeconf);
+       else if (sc->sc_dturbo || (sc->sc_curchan.privFlags & CHANNEL_ST))
+               ath_hal_setslottime(ah, HAL_SLOT_TIME_6);
        else if (ic->ic_flags & IEEE80211_F_SHSLOT)
                ath_hal_setslottime(ah, HAL_SLOT_TIME_9);
        else
                ath_hal_setslottime(ah, HAL_SLOT_TIME_20);
        sc->sc_updateslot = OK;
+       ath_setacktimeout(sc);
+       ath_setctstimeout(sc);
+}
+
+/*
+ * Set the ACK timeout based on the current setting.
+ */
+static void
+ath_setacktimeout(struct ath_softc *sc)
+{
+       struct ath_hal *ah = sc->sc_ah;
+
+       if (sc->sc_acktimeoutconf > 0) /* manual override */
+               ath_hal_setacktimeout(ah, sc->sc_acktimeoutconf);
+       else
+               ath_hal_setacktimeout(ah, ath_default_ctsack_timeout(sc));
+}
+
+/*
+ * Set the CTS timeout based on the current setting.
+ */
+static void
+ath_setctstimeout(struct ath_softc *sc)
+{
+       struct ath_hal *ah = sc->sc_ah;
+
+       if (sc->sc_ctstimeoutconf > 0) /* manual override */
+               ath_hal_setctstimeout(ah, sc->sc_ctstimeoutconf);
+       else
+               ath_hal_setctstimeout(ah, ath_default_ctsack_timeout(sc));
 }
 
 /*
@@ -10545,8 +10630,71 @@ enum {
        ATH_RADAR_IGNORED       = 25,
        ATH_MAXVAPS             = 26,
         ATH_INTMIT             = 27,
+       ATH_DISTANCE            = 28,
 };
 
+static inline int 
+ath_ccatime(struct ath_softc *sc)
+{
+       if (((sc->sc_curchan.channelFlags & IEEE80211_CHAN_PUREG) == 
+           IEEE80211_CHAN_PUREG) && 
+           (sc->sc_ic.ic_flags & IEEE80211_F_SHSLOT))
+               return CCA_PUREG;
+       if ((sc->sc_curchan.channelFlags & IEEE80211_CHAN_A) == 
+           IEEE80211_CHAN_A)
+               return CCA_A;
+
+       return CCA_BG;
+}
+
+static inline int 
+ath_estimate_max_distance(struct ath_softc *sc)
+{
+       /* Prefer overrided, ask HAL if not overridden */
+       int slottime = sc->sc_slottimeconf;
+       if (slottime <= 0)
+               slottime = ath_hal_getslottime(sc->sc_ah);
+       /* NB: We ignore MAC overhead.  this function is reverse operation of 
+        * ath_distance2slottime, and assumes slottime is CCA + 2x air propagation. */
+       return (slottime - ath_ccatime(sc)) * 150;
+}
+
+static inline int 
+ath_distance2slottime(struct ath_softc *sc, int distance)
+{
+
+       /* Allowance for air propagation (roundtrip time) should be at least 
+        * 5us per the standards.
+        * 
+        * So let's set a minimum distance to accomodate this: 
+        * 
+        * roundtrip time = ( ( distance / speed_of_light ) * 2 )
+        *
+        * distance = ( (time * 300 ) / 2) or ((5 * 300) / 2) = 750 m
+        */
+       int rtdist = distance * 2;
+       int aAirPropagation =   (rtdist / 300) + !!(rtdist % 300);
+       if (aAirPropagation < 5) {
+               aAirPropagation = 5;
+       }
+       /* NB: We ignore MAC processing delays... no clue */
+       return ath_ccatime(sc) + aAirPropagation;
+}
+
+static inline int 
+ath_distance2timeout(struct ath_softc *sc, int distance)
+{
+       /* HAL uses a constant of twice slot time plus 18us.
+        * The 18us covers rxtx turnaround, MIB processing, etc.
+        * but the athctrl used to return 2slot+3 so the extra 15us of 
+        * timeout is probably just being very careful or taking something into
+        * account that I can't find in the specs.
+        *
+        * XXX: Update based on emperical evidence (potentially save 15us per timeout)
+        */
+       return ath_slottime2timeout(sc, ath_distance2slottime(sc, distance));
+}
+
 static int
 ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
 {
@@ -10575,25 +10723,75 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
                                lenp, ppos);
                if (ret == 0) {
                        switch ((long)ctl->extra2) {
+                       case ATH_DISTANCE:
+                               if(val > 0) {
+                                       sc->sc_slottimeconf    = ath_distance2slottime(sc, val);
+                                       sc->sc_acktimeoutconf  = ath_distance2timeout(sc, val);
+                                       sc->sc_ctstimeoutconf  = ath_distance2timeout(sc, val);
+                                       ath_setslottime(sc);
+                               }
+                               else {
+                                       /* disable manual overrides */
+                                       sc->sc_slottimeconf   = 0;
+                                       sc->sc_ctstimeoutconf = 0;
+                                       sc->sc_acktimeoutconf = 0;
+                                       ath_setslottime(sc);
+                               }
+                               /* Likely changed by the function */
+                               val = ath_estimate_max_distance(sc);
+                               break;
                        case ATH_SLOTTIME:
                                if (val > 0) {
                                        if (!ath_hal_setslottime(ah, val))
                                                ret = -EINVAL;
-                                       else
+                                       else {
+                                               int old = sc->sc_slottimeconf;
                                                sc->sc_slottimeconf = val;
+                                               /* overridden slot time invalidates 
+                                                * previous overridden ack/cts 
+                                                * timeouts if it is longer! */
+                                               if (old && old < sc->sc_slottimeconf) {
+                                                       sc->sc_ctstimeoutconf = 0;
+                                                       sc->sc_acktimeoutconf = 0;
+                                                       ath_setacktimeout(sc);
+                                                       ath_setctstimeout(sc);
+                                               }
+                                       }
                                } else {
                                        /* disable manual override */
                                        sc->sc_slottimeconf = 0;
                                        ath_setslottime(sc);
                                }
+                               /* Likely changed by the function */
+                               val = ath_getslottime(sc);
                                break;
                        case ATH_ACKTIMEOUT:
-                               if (!ath_hal_setacktimeout(ah, val))
-                                       ret = -EINVAL;
+                               if (val > 0) {
+                                       if (!ath_hal_setacktimeout(ah, val))
+                                               ret = -EINVAL;
+                                       else 
+                                               sc->sc_acktimeoutconf = val;
+                               } else {
+                                       /* disable manual overrider */
+                                       sc->sc_acktimeoutconf = 0;
+                                       ath_setacktimeout(sc);
+                               }
+                               /* Likely changed by the function */
+                               val = ath_getacktimeout(sc);
                                break;
                        case ATH_CTSTIMEOUT:
-                               if (!ath_hal_setctstimeout(ah, val))
-                                       ret = -EINVAL;
+                               if (val > 0) {
+                                       if (!ath_hal_setctstimeout(ah, val))
+                                               ret = -EINVAL;
+                                       else 
+                                               sc->sc_ctstimeoutconf = val;
+                               } else {
+                                       /* disable manual overrides */
+                                       sc->sc_ctstimeoutconf = 0;
+                                       ath_setctstimeout(sc);
+                               }
+                               /* Likely changed by the function */
+                               val = ath_getctstimeout(sc);
                                break;
                        case ATH_SOFTLED:
                                if (val != sc->sc_softled) {
@@ -10757,14 +10955,17 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
                }
        } else {
                switch ((long)ctl->extra2) {
+               case ATH_DISTANCE:
+                       val = ath_estimate_max_distance(sc);
+                       break;
                case ATH_SLOTTIME:
-                       val = ath_hal_getslottime(ah);
+                       val = ath_getslottime(sc);
                        break;
                case ATH_ACKTIMEOUT:
-                       val = ath_hal_getacktimeout(ah);
+                       val = ath_getacktimeout(sc);
                        break;
                case ATH_CTSTIMEOUT:
-                       val = ath_hal_getctstimeout(ah);
+                       val = ath_getctstimeout(sc);
                        break;
                case ATH_SOFTLED:
                        val = sc->sc_softled;
@@ -10836,6 +11037,12 @@ static int mincalibrate = 1;           /* once a second */
 static int maxint = 0x7fffffff;                /* 32-bit big */
 
 static const ctl_table ath_sysctl_template[] = {
+       { .ctl_name     = CTL_AUTO,
+         .procname     = "distance",
+         .mode         = 0644,
+         .proc_handler = ath_sysctl_halparam,
+         .extra2       = (void *)ATH_DISTANCE,
+       },
        { .ctl_name     = CTL_AUTO,
          .procname     = "slottime",
          .mode         = 0644,
index 599ab172510eb54f6121c2869fcf9592535a012a..4c1cd51bef4cd8d4eec6597e311e7d9d4641b66a 100644 (file)
@@ -295,6 +295,12 @@ static inline struct net_device *_alloc_netdev(int sizeof_priv, const char *mask
 #define GRP_POLL_PERIOD_NO_XR_STA_MAX  100
 #define GRP_POLL_PERIOD_XR_STA_MAX     30
 
+enum {
+       CCA_BG    = 15,
+       CCA_A     = 4,
+       CCA_PUREG = 4, /* pure G */
+};
+
  /*
  * Percentage of the configured poll periodicity
  */
@@ -335,7 +341,6 @@ static inline struct net_device *_alloc_netdev(int sizeof_priv, const char *mask
 #define MIN_REGISTER_ADDRESS   0x0000          /* PCI register addresses are taken as releative to the appropriate BAR */
 #define MAX_REGISTER_ADDRESS   0xc000          /* AR5212/AR5213 seems to have a 48k address range */
 #define MAX_REGISTER_NAME_LEN  32              /* Maximum length of register nicknames in debug output */
-#define UNKNOWN_NAME           "(unknown)"     /* Name used when reading/listing undocumented registers */
 #endif /* #ifdef ATH_REVERSE_ENGINEERING */
 /*
  * Convert from net80211 layer values to Ath layer values. Hopefully this will
@@ -800,6 +805,8 @@ struct ath_softc {
        u_int32_t sc_dturbo_bw_turbo;           /* bandwidth threshold */
 #endif
        u_int sc_slottimeconf;                  /* manual override for slottime */
+       u_int sc_acktimeoutconf;                /* manual override for ack timeout */
+       u_int sc_ctstimeoutconf;                /* manual override for cts timeout */
 
        struct timer_list sc_dfs_excl_timer;    /* mark expiration timer task */
        struct timer_list sc_dfs_cac_timer;     /* dfs wait timer */
index 8a7dfe3482aaa657d792f8f41b220c16a4a7f371..862f0181be69a4e79e1be300d0c4e2361b1d0098 100644 (file)
@@ -117,15 +117,9 @@ main(int argc, char *argv[])
        }
 
        if (distance >= 0) {
-               int slottime = 9 + (distance / 300) + ((distance % 300) ? 1 : 0);
-               int acktimeout = slottime * 2 + 3;
-               int ctstimeout = slottime * 2 + 3;
-
                printf("Setting distance on interface %s to %i meters\n",
                        device, distance);
-               setsysctrl(device, "slottime", slottime);
-               setsysctrl(device, "acktimeout", acktimeout);
-               setsysctrl(device, "ctstimeout", ctstimeout);
+               setsysctrl(device, "distance", distance);
        } else
                usage();
        return 0;