madwifi: add sysctl for turning the radio silent
[openwrt.git] / package / madwifi / patches / 454-cca.patch
1 --- a/ath/if_ath.c
2 +++ b/ath/if_ath.c
3 @@ -383,6 +383,8 @@ static void ath_poll_disable(struct net_
4  static void ath_poll_enable(struct net_device *dev);
5  static void ath_fetch_idle_time(struct ath_softc *sc);
6  static void ath_set_timing(struct ath_softc *sc);
7 +static void ath_update_cca_thresh(struct ath_softc *sc);
8 +static int ath_hw_read_nf(struct ath_softc *sc);
9  
10  /* calibrate every 30 secs in steady state but check every second at first. */
11  static int ath_calinterval = ATH_SHORT_CALINTERVAL;
12 @@ -2623,6 +2625,10 @@ ath_init(struct net_device *dev)
13                 goto done;
14         }
15  
16 +       ath_hal_process_noisefloor(ah);
17 +       ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
18 +       ath_update_cca_thresh(sc);
19 +
20         if (sc->sc_softled)
21                 ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
22  
23 @@ -3024,6 +3030,10 @@ ath_reset(struct net_device *dev)
24                 EPRINTF(sc, "Unable to reset hardware: '%s' (HAL status %u)\n",
25                         ath_get_hal_status_desc(status), status);
26  
27 +       ath_hal_process_noisefloor(ah);
28 +       ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
29 +       ath_update_cca_thresh(sc);
30 +
31         ath_setintmit(sc);
32         ath_update_txpow(sc);           /* update tx power state */
33         ath_radar_update(sc);
34 @@ -9374,9 +9384,11 @@ ath_calibrate(unsigned long arg)
35                         sc->sc_curchan.channel);
36                 sc->sc_stats.ast_per_calfail++;
37         }
38 -       ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
39  
40         ath_hal_process_noisefloor(ah);
41 +       ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
42 +       ath_update_cca_thresh(sc);
43 +
44         if (isIQdone == AH_TRUE) {
45                 /* Unless user has overridden calibration interval,
46                  * upgrade to less frequent calibration */
47 @@ -9711,8 +9723,6 @@ ath_newstate(struct ieee80211vap *vap, e
48                         break;
49                 }
50  
51 -               ath_hal_process_noisefloor(ah);
52 -               ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
53                 /*
54                  * Reset rssi stats; maybe not the best place...
55                  */
56 @@ -10968,6 +10978,7 @@ enum {
57         ATH_INTMIT,
58         ATH_NOISE_IMMUNITY,
59         ATH_OFDM_WEAK_DET,
60 +       ATH_CCA_THRESH,
61         ATH_CHANBW,
62         ATH_OUTDOOR,
63         ATH_DISTANCE,
64 @@ -11110,6 +11121,66 @@ ath_sysctl_get_intmit(struct ath_softc *
65         return 0;
66  }
67  
68 +#define AR_PHY_CCA              0x9864
69 +#define AR_PHY_MINCCA_PWR       0x0FF80000
70 +#define AR_PHY_MINCCA_PWR_S     19
71 +#define AR_PHY_CCA_THRESH62     0x0007F000
72 +#define AR_PHY_CCA_THRESH62_S   12
73 +
74 +static int
75 +ath_nf_from_cca(u32 phy_cca)
76 +{
77 +       int nf = (phy_cca >> 19) & 0x1ff;
78 +       nf = -((nf ^ 0x1ff) + 1);
79 +       return nf;
80 +}
81 +
82 +static int
83 +ath_hw_read_nf(struct ath_softc *sc)
84 +{
85 +       return ath_nf_from_cca(OS_REG_READ(sc->sc_ah, AR_PHY_CCA));
86 +}
87 +
88 +static void
89 +ath_update_cca_thresh(struct ath_softc *sc)
90 +{
91 +       struct ath_hal *ah = sc->sc_ah;
92 +       int newthr = 0;
93 +       u32 phy_cca;
94 +       int nf;
95 +
96 +       phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
97 +       if (sc->sc_cca_thresh < 0) {
98 +               newthr = sc->sc_cca_thresh - ath_nf_from_cca(phy_cca);
99 +
100 +               /* 0xf is a typical eeprom value for thresh62,
101 +                * use it as minimum for signal based thresholds
102 +                * to prevent complete connection drops */
103 +               if (newthr < 0xf)
104 +                       newthr = 0xf;
105 +       } else {
106 +               newthr = sc->sc_cca_thresh;
107 +       }
108 +
109 +       if ((newthr < 4) || (newthr >= 127))
110 +               return;
111 +
112 +       phy_cca &= ~AR_PHY_CCA_THRESH62;
113 +       phy_cca |= newthr << AR_PHY_CCA_THRESH62_S;
114 +       OS_REG_WRITE(ah, AR_PHY_CCA, phy_cca);
115 +}
116 +
117 +static int
118 +ath_get_cca_thresh(struct ath_softc *sc)
119 +{
120 +       struct ath_hal *ah = sc->sc_ah;
121 +       u32 phy_cca;
122 +
123 +       phy_cca = OS_REG_READ(ah, AR_PHY_CCA);
124 +       return ath_nf_from_cca(phy_cca) +
125 +               ((phy_cca & AR_PHY_CCA_THRESH62) >> AR_PHY_CCA_THRESH62_S);
126 +}
127 +
128  static int
129  ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos)
130  {
131 @@ -11356,6 +11427,10 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
132                         case ATH_OFDM_WEAK_DET:
133                                 ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
134                                 break;
135 +                       case ATH_CCA_THRESH:
136 +                               sc->sc_cca_thresh = val;
137 +                               ath_update_cca_thresh(sc);
138 +                               break;
139                         default:
140                                 ret = -EINVAL;
141                                 break;
142 @@ -11436,6 +11511,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl
143                 case ATH_OFDM_WEAK_DET:
144                         ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
145                         break;
146 +               case ATH_CCA_THRESH:
147 +                       val = ath_get_cca_thresh(sc);
148 +                       break;
149                 default:
150                         ret = -EINVAL;
151                         break;
152 @@ -11667,6 +11745,12 @@ static const ctl_table ath_sysctl_templa
153           .proc_handler = ath_sysctl_halparam,
154           .extra2       = (void *)ATH_OFDM_WEAK_DET,
155         },
156 +       { .ctl_name     = CTL_AUTO,
157 +         .procname     = "cca_thresh",
158 +         .mode         = 0644,
159 +         .proc_handler = ath_sysctl_halparam,
160 +         .extra2       = (void *)ATH_CCA_THRESH,
161 +       },
162         { 0 }
163  };
164  
165 --- a/ath/if_athvar.h
166 +++ b/ath/if_athvar.h
167 @@ -844,6 +844,7 @@ struct ath_softc {
168         int sc_cal_interval;                    /* current calibration interval */
169         struct timer_list sc_cal_ch;            /* calibration timer */
170         HAL_NODE_STATS sc_halstats;             /* station-mode rssi stats */
171 +       int sc_cca_thresh;                              /* configured CCA threshold */
172  
173         struct ctl_table_header *sc_sysctl_header;
174         struct ctl_table *sc_sysctls;
175 --- a/ath/ath_wprobe.c
176 +++ b/ath/ath_wprobe.c
177 @@ -133,8 +133,7 @@ ath_wprobe_sync(struct wprobe_iface *dev
178         rx = READ_CLR(ah, AR5K_RXFC);
179         tx = READ_CLR(ah, AR5K_TXFC);
180         OS_REG_WRITE(ah, AR5K_MIBC, 0);
181 -       noise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
182 -       ic->ic_channoise = noise;
183 +       noise = ath_hw_read_nf(sc);
184  
185         WPROBE_FILL_BEGIN(val, ath_wprobe_globals);
186         if (cc & 0xf0000000) {