Commit | Line | Data |
---|---|---|
88adc104 GKH |
1 | #include "r8180_dm.h" |
2 | #include "r8180_hw.h" | |
3 | #include "r8180_93cx6.h" | |
da45e3fe | 4 | |
ed2cb4f3 | 5 | /* Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */ |
88adc104 GKH |
6 | #define RATE_ADAPTIVE_TIMER_PERIOD 300 |
7 | ||
8 | bool CheckHighPower(struct net_device *dev) | |
9 | { | |
10 | struct r8180_priv *priv = ieee80211_priv(dev); | |
11 | struct ieee80211_device *ieee = priv->ieee80211; | |
12 | ||
9cf66a95 | 13 | if (!priv->bRegHighPowerMechanism) |
88adc104 | 14 | return false; |
88adc104 | 15 | |
9cf66a95 | 16 | if (ieee->state == IEEE80211_LINKED_SCANNING) |
88adc104 | 17 | return false; |
88adc104 GKH |
18 | |
19 | return true; | |
20 | } | |
21 | ||
da45e3fe AM |
22 | /* |
23 | * Description: | |
24 | * Update Tx power level if necessary. | |
25 | * See also DoRxHighPower() and SetTxPowerLevel8185() for reference. | |
26 | * | |
27 | * Note: | |
28 | * The reason why we udpate Tx power level here instead of DoRxHighPower() | |
29 | * is the number of IO to change Tx power is much more than channel TR switch | |
30 | * and they are related to OFDM and MAC registers. | |
31 | * So, we don't want to update it so frequently in per-Rx packet base. | |
32 | */ | |
17ab33ee | 33 | static void DoTxHighPower(struct net_device *dev) |
88adc104 GKH |
34 | { |
35 | struct r8180_priv *priv = ieee80211_priv(dev); | |
36 | u16 HiPwrUpperTh = 0; | |
37 | u16 HiPwrLowerTh = 0; | |
38 | u8 RSSIHiPwrUpperTh; | |
39 | u8 RSSIHiPwrLowerTh; | |
40 | u8 u1bTmp; | |
41 | char OfdmTxPwrIdx, CckTxPwrIdx; | |
42 | ||
88adc104 GKH |
43 | HiPwrUpperTh = priv->RegHiPwrUpperTh; |
44 | HiPwrLowerTh = priv->RegHiPwrLowerTh; | |
45 | ||
46 | HiPwrUpperTh = HiPwrUpperTh * 10; | |
47 | HiPwrLowerTh = HiPwrLowerTh * 10; | |
48 | RSSIHiPwrUpperTh = priv->RegRSSIHiPwrUpperTh; | |
49 | RSSIHiPwrLowerTh = priv->RegRSSIHiPwrLowerTh; | |
50 | ||
da45e3fe | 51 | /* lzm add 080826 */ |
88adc104 GKH |
52 | OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; |
53 | CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; | |
54 | ||
536d190d | 55 | if ((priv->UndecoratedSmoothedSS > HiPwrUpperTh) || |
aada7fdd | 56 | (priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh))) { |
da45e3fe | 57 | /* Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah */ |
88adc104 | 58 | |
88adc104 | 59 | priv->bToUpdateTxPwr = true; |
9cf66a95 | 60 | u1bTmp = read_nic_byte(dev, CCK_TXAGC); |
88adc104 | 61 | |
da45e3fe | 62 | /* If it never enter High Power. */ |
536d190d | 63 | if (CckTxPwrIdx == u1bTmp) { |
9cf66a95 | 64 | u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ |
1748d2de | 65 | write_nic_byte(dev, CCK_TXAGC, u1bTmp); |
88adc104 | 66 | |
9cf66a95 AR |
67 | u1bTmp = read_nic_byte(dev, OFDM_TXAGC); |
68 | u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ | |
1748d2de | 69 | write_nic_byte(dev, OFDM_TXAGC, u1bTmp); |
88adc104 GKH |
70 | } |
71 | ||
536d190d | 72 | } else if ((priv->UndecoratedSmoothedSS < HiPwrLowerTh) && |
aada7fdd | 73 | (!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh)) { |
536d190d | 74 | if (priv->bToUpdateTxPwr) { |
88adc104 | 75 | priv->bToUpdateTxPwr = false; |
da45e3fe | 76 | /* SD3 required. */ |
9cf66a95 | 77 | u1bTmp = read_nic_byte(dev, CCK_TXAGC); |
536d190d | 78 | if (u1bTmp < CckTxPwrIdx) { |
1748d2de | 79 | write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx); |
88adc104 GKH |
80 | } |
81 | ||
9cf66a95 | 82 | u1bTmp = read_nic_byte(dev, OFDM_TXAGC); |
536d190d | 83 | if (u1bTmp < OfdmTxPwrIdx) { |
1748d2de | 84 | write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); |
88adc104 GKH |
85 | } |
86 | } | |
87 | } | |
88adc104 GKH |
88 | } |
89 | ||
90 | ||
da45e3fe AM |
91 | /* |
92 | * Description: | |
93 | * Callback function of UpdateTxPowerWorkItem. | |
94 | * Because of some event happened, e.g. CCX TPC, High Power Mechanism, | |
95 | * We update Tx power of current channel again. | |
96 | */ | |
536d190d | 97 | void rtl8180_tx_pw_wq(struct work_struct *work) |
88adc104 | 98 | { |
5f546031 | 99 | struct delayed_work *dwork = to_delayed_work(work); |
9cf66a95 | 100 | struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, tx_pw_wq); |
1748d2de | 101 | struct net_device *dev = ieee->dev; |
88adc104 | 102 | |
88adc104 | 103 | DoTxHighPower(dev); |
88adc104 GKH |
104 | } |
105 | ||
106 | ||
da45e3fe | 107 | /* |
ed2cb4f3 | 108 | * Return TRUE if we shall perform DIG Mechanism, FALSE otherwise. |
da45e3fe | 109 | */ |
536d190d | 110 | bool CheckDig(struct net_device *dev) |
88adc104 GKH |
111 | { |
112 | struct r8180_priv *priv = ieee80211_priv(dev); | |
113 | struct ieee80211_device *ieee = priv->ieee80211; | |
114 | ||
536d190d | 115 | if (!priv->bDigMechanism) |
88adc104 GKH |
116 | return false; |
117 | ||
536d190d | 118 | if (ieee->state != IEEE80211_LINKED) |
88adc104 GKH |
119 | return false; |
120 | ||
da45e3fe | 121 | if ((priv->ieee80211->rate / 5) < 36) /* Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. */ |
88adc104 GKH |
122 | return false; |
123 | return true; | |
124 | } | |
da45e3fe | 125 | /* |
3e837dca | 126 | * Implementation of DIG for Zebra and Zebra2. |
da45e3fe | 127 | */ |
17ab33ee | 128 | static void DIG_Zebra(struct net_device *dev) |
88adc104 GKH |
129 | { |
130 | struct r8180_priv *priv = ieee80211_priv(dev); | |
131 | u16 CCKFalseAlarm, OFDMFalseAlarm; | |
132 | u16 OfdmFA1, OfdmFA2; | |
da45e3fe AM |
133 | int InitialGainStep = 7; /* The number of initial gain stages. */ |
134 | int LowestGainStage = 4; /* The capable lowest stage of performing dig workitem. */ | |
536d190d | 135 | u32 AwakePeriodIn2Sec = 0; |
88adc104 | 136 | |
88adc104 GKH |
137 | CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff); |
138 | OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff); | |
139 | OfdmFA1 = 0x15; | |
140 | OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8; | |
141 | ||
da45e3fe AM |
142 | /* The number of initial gain steps is different, by Bruce, 2007-04-13. */ |
143 | if (priv->InitialGain == 0) { /* autoDIG */ | |
144 | /* Advised from SD3 DZ */ | |
145 | priv->InitialGain = 4; /* In 87B, m74dBm means State 4 (m82dBm) */ | |
88adc104 | 146 | } |
da45e3fe | 147 | /* Advised from SD3 DZ */ |
536d190d | 148 | OfdmFA1 = 0x20; |
88adc104 | 149 | |
da45e3fe | 150 | #if 1 /* lzm reserved 080826 */ |
536d190d | 151 | AwakePeriodIn2Sec = (2000 - priv->DozePeriodInPast2Sec); |
9cf66a95 | 152 | priv->DozePeriodInPast2Sec = 0; |
88adc104 | 153 | |
536d190d | 154 | if (AwakePeriodIn2Sec) { |
9cf66a95 AR |
155 | OfdmFA1 = (u16)((OfdmFA1 * AwakePeriodIn2Sec) / 2000); |
156 | OfdmFA2 = (u16)((OfdmFA2 * AwakePeriodIn2Sec) / 2000); | |
aada7fdd | 157 | } else { |
3e837dca | 158 | ; |
88adc104 GKH |
159 | } |
160 | #endif | |
161 | ||
162 | InitialGainStep = 8; | |
da45e3fe | 163 | LowestGainStage = priv->RegBModeGainStage; /* Lowest gain stage. */ |
88adc104 | 164 | |
aada7fdd AM |
165 | if (OFDMFalseAlarm > OfdmFA1) { |
166 | if (OFDMFalseAlarm > OfdmFA2) { | |
88adc104 | 167 | priv->DIG_NumberFallbackVote++; |
536d190d | 168 | if (priv->DIG_NumberFallbackVote > 1) { |
da45e3fe | 169 | /* serious OFDM False Alarm, need fallback */ |
aada7fdd | 170 | if (priv->InitialGain < InitialGainStep) { |
536d190d | 171 | priv->InitialGainBackUp = priv->InitialGain; |
88adc104 GKH |
172 | |
173 | priv->InitialGain = (priv->InitialGain + 1); | |
88adc104 GKH |
174 | UpdateInitialGain(dev); |
175 | } | |
176 | priv->DIG_NumberFallbackVote = 0; | |
536d190d | 177 | priv->DIG_NumberUpgradeVote = 0; |
88adc104 | 178 | } |
aada7fdd | 179 | } else { |
88adc104 GKH |
180 | if (priv->DIG_NumberFallbackVote) |
181 | priv->DIG_NumberFallbackVote--; | |
182 | } | |
536d190d | 183 | priv->DIG_NumberUpgradeVote = 0; |
aada7fdd | 184 | } else { |
88adc104 GKH |
185 | if (priv->DIG_NumberFallbackVote) |
186 | priv->DIG_NumberFallbackVote--; | |
187 | priv->DIG_NumberUpgradeVote++; | |
188 | ||
536d190d | 189 | if (priv->DIG_NumberUpgradeVote > 9) { |
da45e3fe | 190 | if (priv->InitialGain > LowestGainStage) { /* In 87B, m78dBm means State 4 (m864dBm) */ |
536d190d | 191 | priv->InitialGainBackUp = priv->InitialGain; |
88adc104 GKH |
192 | |
193 | priv->InitialGain = (priv->InitialGain - 1); | |
88adc104 GKH |
194 | UpdateInitialGain(dev); |
195 | } | |
196 | priv->DIG_NumberFallbackVote = 0; | |
536d190d | 197 | priv->DIG_NumberUpgradeVote = 0; |
88adc104 GKH |
198 | } |
199 | } | |
88adc104 GKH |
200 | } |
201 | ||
da45e3fe | 202 | /* |
3e837dca | 203 | * Dispatch DIG implementation according to RF. |
da45e3fe | 204 | */ |
17ab33ee | 205 | static void DynamicInitGain(struct net_device *dev) |
88adc104 | 206 | { |
8daba6b9 | 207 | DIG_Zebra(dev); |
88adc104 GKH |
208 | } |
209 | ||
536d190d | 210 | void rtl8180_hw_dig_wq(struct work_struct *work) |
88adc104 | 211 | { |
5f546031 | 212 | struct delayed_work *dwork = to_delayed_work(work); |
9cf66a95 | 213 | struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_dig_wq); |
1748d2de | 214 | struct net_device *dev = ieee->dev; |
88adc104 GKH |
215 | struct r8180_priv *priv = ieee80211_priv(dev); |
216 | ||
da45e3fe | 217 | /* Read CCK and OFDM False Alarm. */ |
88adc104 GKH |
218 | priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM); |
219 | ||
220 | ||
da45e3fe | 221 | /* Adjust Initial Gain dynamically. */ |
88adc104 GKH |
222 | DynamicInitGain(dev); |
223 | ||
224 | } | |
225 | ||
17ab33ee | 226 | static int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate) |
88adc104 | 227 | { |
1748d2de AM |
228 | u8 rate_len; |
229 | u8 rate_ex_len; | |
230 | u8 RateMask = 0x7F; | |
231 | u8 idx; | |
232 | unsigned short Found = 0; | |
233 | u8 NaiveTxRate = TxRate&RateMask; | |
234 | ||
235 | rate_len = priv->ieee80211->current_network.rates_len; | |
236 | rate_ex_len = priv->ieee80211->current_network.rates_ex_len; | |
9cf66a95 | 237 | for (idx = 0; idx < rate_len; idx++) { |
536d190d | 238 | if ((priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate) { |
1748d2de AM |
239 | Found = 1; |
240 | goto found_rate; | |
241 | } | |
242 | } | |
536d190d AM |
243 | for (idx = 0; idx < rate_ex_len; idx++) { |
244 | if ((priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate) { | |
1748d2de AM |
245 | Found = 1; |
246 | goto found_rate; | |
247 | } | |
248 | } | |
249 | return Found; | |
9cf66a95 | 250 | found_rate: |
1748d2de | 251 | return Found; |
88adc104 GKH |
252 | } |
253 | ||
da45e3fe | 254 | /* |
3e837dca AM |
255 | * Get the Tx rate one degree up form the input rate in the supported rates. |
256 | * Return the upgrade rate if it is successed, otherwise return the input rate. | |
da45e3fe | 257 | */ |
17ab33ee | 258 | static u8 GetUpgradeTxRate(struct net_device *dev, u8 rate) |
88adc104 | 259 | { |
1748d2de AM |
260 | struct r8180_priv *priv = ieee80211_priv(dev); |
261 | u8 UpRate; | |
262 | ||
da45e3fe | 263 | /* Upgrade 1 degree. */ |
536d190d | 264 | switch (rate) { |
da45e3fe | 265 | case 108: /* Up to 54Mbps. */ |
1748d2de AM |
266 | UpRate = 108; |
267 | break; | |
268 | ||
da45e3fe | 269 | case 96: /* Up to 54Mbps. */ |
1748d2de AM |
270 | UpRate = 108; |
271 | break; | |
272 | ||
da45e3fe | 273 | case 72: /* Up to 48Mbps. */ |
1748d2de AM |
274 | UpRate = 96; |
275 | break; | |
276 | ||
da45e3fe | 277 | case 48: /* Up to 36Mbps. */ |
1748d2de AM |
278 | UpRate = 72; |
279 | break; | |
280 | ||
da45e3fe | 281 | case 36: /* Up to 24Mbps. */ |
1748d2de AM |
282 | UpRate = 48; |
283 | break; | |
284 | ||
da45e3fe | 285 | case 22: /* Up to 18Mbps. */ |
1748d2de AM |
286 | UpRate = 36; |
287 | break; | |
288 | ||
da45e3fe | 289 | case 11: /* Up to 11Mbps. */ |
1748d2de AM |
290 | UpRate = 22; |
291 | break; | |
292 | ||
da45e3fe | 293 | case 4: /* Up to 5.5Mbps. */ |
1748d2de AM |
294 | UpRate = 11; |
295 | break; | |
296 | ||
da45e3fe | 297 | case 2: /* Up to 2Mbps. */ |
1748d2de AM |
298 | UpRate = 4; |
299 | break; | |
300 | ||
301 | default: | |
302 | printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); | |
303 | return rate; | |
304 | } | |
da45e3fe | 305 | /* Check if the rate is valid. */ |
536d190d | 306 | if (IncludedInSupportedRates(priv, UpRate)) { |
1748d2de AM |
307 | return UpRate; |
308 | } else { | |
1748d2de AM |
309 | return rate; |
310 | } | |
311 | return rate; | |
88adc104 | 312 | } |
da45e3fe | 313 | /* |
3e837dca AM |
314 | * Get the Tx rate one degree down form the input rate in the supported rates. |
315 | * Return the degrade rate if it is successed, otherwise return the input rate. | |
da45e3fe AM |
316 | */ |
317 | ||
17ab33ee | 318 | static u8 GetDegradeTxRate(struct net_device *dev, u8 rate) |
88adc104 | 319 | { |
1748d2de AM |
320 | struct r8180_priv *priv = ieee80211_priv(dev); |
321 | u8 DownRate; | |
322 | ||
da45e3fe | 323 | /* Upgrade 1 degree. */ |
536d190d | 324 | switch (rate) { |
da45e3fe | 325 | case 108: /* Down to 48Mbps. */ |
1748d2de AM |
326 | DownRate = 96; |
327 | break; | |
328 | ||
da45e3fe | 329 | case 96: /* Down to 36Mbps. */ |
1748d2de AM |
330 | DownRate = 72; |
331 | break; | |
332 | ||
da45e3fe | 333 | case 72: /* Down to 24Mbps. */ |
1748d2de AM |
334 | DownRate = 48; |
335 | break; | |
336 | ||
da45e3fe | 337 | case 48: /* Down to 18Mbps. */ |
1748d2de AM |
338 | DownRate = 36; |
339 | break; | |
340 | ||
da45e3fe | 341 | case 36: /* Down to 11Mbps. */ |
1748d2de AM |
342 | DownRate = 22; |
343 | break; | |
344 | ||
da45e3fe | 345 | case 22: /* Down to 5.5Mbps. */ |
1748d2de AM |
346 | DownRate = 11; |
347 | break; | |
348 | ||
da45e3fe | 349 | case 11: /* Down to 2Mbps. */ |
1748d2de AM |
350 | DownRate = 4; |
351 | break; | |
352 | ||
da45e3fe | 353 | case 4: /* Down to 1Mbps. */ |
1748d2de AM |
354 | DownRate = 2; |
355 | break; | |
356 | ||
da45e3fe | 357 | case 2: /* Down to 1Mbps. */ |
1748d2de AM |
358 | DownRate = 2; |
359 | break; | |
360 | ||
361 | default: | |
362 | printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); | |
363 | return rate; | |
364 | } | |
da45e3fe | 365 | /* Check if the rate is valid. */ |
536d190d | 366 | if (IncludedInSupportedRates(priv, DownRate)) { |
1748d2de AM |
367 | return DownRate; |
368 | } else { | |
1748d2de AM |
369 | return rate; |
370 | } | |
371 | return rate; | |
88adc104 | 372 | } |
da45e3fe AM |
373 | /* |
374 | * Helper function to determine if specified data rate is | |
375 | * CCK rate. | |
da45e3fe AM |
376 | */ |
377 | ||
17ab33ee | 378 | static bool MgntIsCckRate(u16 rate) |
88adc104 | 379 | { |
1748d2de | 380 | bool bReturn = false; |
88adc104 | 381 | |
536d190d | 382 | if ((rate <= 22) && (rate != 12) && (rate != 18)) { |
1748d2de AM |
383 | bReturn = true; |
384 | } | |
88adc104 | 385 | |
1748d2de | 386 | return bReturn; |
88adc104 | 387 | } |
da45e3fe AM |
388 | /* |
389 | * Description: | |
390 | * Tx Power tracking mechanism routine on 87SE. | |
da45e3fe | 391 | */ |
536d190d | 392 | void TxPwrTracking87SE(struct net_device *dev) |
88adc104 GKH |
393 | { |
394 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
395 | u8 tmpu1Byte, CurrentThermal, Idx; | |
396 | char CckTxPwrIdx, OfdmTxPwrIdx; | |
88adc104 GKH |
397 | |
398 | tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL); | |
da45e3fe | 399 | CurrentThermal = (tmpu1Byte & 0xf0) >> 4; /*[ 7:4]: thermal meter indication. */ |
9cf66a95 | 400 | CurrentThermal = (CurrentThermal > 0x0c) ? 0x0c : CurrentThermal;/* lzm add 080826 */ |
88adc104 | 401 | |
536d190d | 402 | if (CurrentThermal != priv->ThermalMeter) { |
da45e3fe | 403 | /* Update Tx Power level on each channel. */ |
536d190d | 404 | for (Idx = 1; Idx < 15; Idx++) { |
88adc104 GKH |
405 | CckTxPwrIdx = priv->chtxpwr[Idx]; |
406 | OfdmTxPwrIdx = priv->chtxpwr_ofdm[Idx]; | |
407 | ||
536d190d | 408 | if (CurrentThermal > priv->ThermalMeter) { |
da45e3fe | 409 | /* higher thermal meter. */ |
536d190d AM |
410 | CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2; |
411 | OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2; | |
88adc104 | 412 | |
536d190d | 413 | if (CckTxPwrIdx > 35) |
da45e3fe | 414 | CckTxPwrIdx = 35; /* Force TxPower to maximal index. */ |
536d190d | 415 | if (OfdmTxPwrIdx > 35) |
88adc104 | 416 | OfdmTxPwrIdx = 35; |
aada7fdd | 417 | } else { |
da45e3fe | 418 | /* lower thermal meter. */ |
536d190d AM |
419 | CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2; |
420 | OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2; | |
88adc104 | 421 | |
536d190d | 422 | if (CckTxPwrIdx < 0) |
88adc104 | 423 | CckTxPwrIdx = 0; |
536d190d | 424 | if (OfdmTxPwrIdx < 0) |
88adc104 GKH |
425 | OfdmTxPwrIdx = 0; |
426 | } | |
427 | ||
da45e3fe | 428 | /* Update TxPower level on CCK and OFDM resp. */ |
88adc104 GKH |
429 | priv->chtxpwr[Idx] = CckTxPwrIdx; |
430 | priv->chtxpwr_ofdm[Idx] = OfdmTxPwrIdx; | |
431 | } | |
432 | ||
da45e3fe | 433 | /* Update TxPower level immediately. */ |
88adc104 GKH |
434 | rtl8225z2_SetTXPowerLevel(dev, priv->ieee80211->current_network.channel); |
435 | } | |
436 | priv->ThermalMeter = CurrentThermal; | |
437 | } | |
17ab33ee | 438 | static void StaRateAdaptive87SE(struct net_device *dev) |
88adc104 GKH |
439 | { |
440 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
1748d2de AM |
441 | unsigned long CurrTxokCnt; |
442 | u16 CurrRetryCnt; | |
443 | u16 CurrRetryRate; | |
1748d2de AM |
444 | unsigned long CurrRxokCnt; |
445 | bool bTryUp = false; | |
446 | bool bTryDown = false; | |
447 | u8 TryUpTh = 1; | |
448 | u8 TryDownTh = 2; | |
449 | u32 TxThroughput; | |
88adc104 GKH |
450 | long CurrSignalStrength; |
451 | bool bUpdateInitialGain = false; | |
536d190d | 452 | u8 u1bOfdm = 0, u1bCck = 0; |
88adc104 GKH |
453 | char OfdmTxPwrIdx, CckTxPwrIdx; |
454 | ||
536d190d | 455 | priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD; |
88adc104 GKH |
456 | |
457 | ||
458 | CurrRetryCnt = priv->CurrRetryCnt; | |
459 | CurrTxokCnt = priv->NumTxOkTotal - priv->LastTxokCnt; | |
460 | CurrRxokCnt = priv->ieee80211->NumRxOkTotal - priv->LastRxokCnt; | |
461 | CurrSignalStrength = priv->Stats_RecvSignalPower; | |
462 | TxThroughput = (u32)(priv->NumTxOkBytesTotal - priv->LastTxOKBytes); | |
463 | priv->LastTxOKBytes = priv->NumTxOkBytesTotal; | |
536d190d | 464 | priv->CurrentOperaRate = priv->ieee80211->rate / 5; |
da45e3fe | 465 | /* 2 Compute retry ratio. */ |
536d190d AM |
466 | if (CurrTxokCnt > 0) { |
467 | CurrRetryRate = (u16)(CurrRetryCnt * 100 / CurrTxokCnt); | |
aada7fdd | 468 | } else { |
da45e3fe | 469 | /* It may be serious retry. To distinguish serious retry or no packets modified by Bruce */ |
536d190d | 470 | CurrRetryRate = (u16)(CurrRetryCnt * 100 / 1); |
88adc104 GKH |
471 | } |
472 | ||
88adc104 GKH |
473 | priv->LastRetryCnt = priv->CurrRetryCnt; |
474 | priv->LastTxokCnt = priv->NumTxOkTotal; | |
475 | priv->LastRxokCnt = priv->ieee80211->NumRxOkTotal; | |
476 | priv->CurrRetryCnt = 0; | |
477 | ||
da45e3fe | 478 | /* 2No Tx packets, return to init_rate or not? */ |
536d190d | 479 | if (CurrRetryRate == 0 && CurrTxokCnt == 0) { |
da45e3fe AM |
480 | /* |
481 | * After 9 (30*300ms) seconds in this condition, we try to raise rate. | |
482 | */ | |
88adc104 GKH |
483 | priv->TryupingCountNoData++; |
484 | ||
da45e3fe | 485 | /* [TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00 */ |
536d190d | 486 | if (priv->TryupingCountNoData > 30) { |
88adc104 | 487 | priv->TryupingCountNoData = 0; |
004c7acb | 488 | priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); |
da45e3fe | 489 | /* Reset Fail Record */ |
88adc104 GKH |
490 | priv->LastFailTxRate = 0; |
491 | priv->LastFailTxRateSS = -200; | |
492 | priv->FailTxRateCount = 0; | |
493 | } | |
494 | goto SetInitialGain; | |
aada7fdd | 495 | } else { |
da45e3fe | 496 | priv->TryupingCountNoData = 0; /*Reset trying up times. */ |
88adc104 GKH |
497 | } |
498 | ||
499 | ||
da45e3fe AM |
500 | /* |
501 | * For Netgear case, I comment out the following signal strength estimation, | |
502 | * which can results in lower rate to transmit when sample is NOT enough (e.g. PING request). | |
da45e3fe AM |
503 | * |
504 | * Restructure rate adaptive as the following main stages: | |
505 | * (1) Add retry threshold in 54M upgrading condition with signal strength. | |
506 | * (2) Add the mechanism to degrade to CCK rate according to signal strength | |
507 | * and retry rate. | |
508 | * (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated | |
509 | * situation, Initial Gain Update is upon on DIG mechanism except CCK rate. | |
ed2cb4f3 | 510 | * (4) Add the mechanism of trying to upgrade tx rate. |
da45e3fe | 511 | * (5) Record the information of upping tx rate to avoid trying upping tx rate constantly. |
da45e3fe AM |
512 | * |
513 | */ | |
514 | ||
515 | /* | |
9cf66a95 | 516 | * 11Mbps or 36Mbps |
da45e3fe AM |
517 | * Check more times in these rate(key rates). |
518 | */ | |
536d190d | 519 | if (priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72) |
88adc104 | 520 | TryUpTh += 9; |
da45e3fe AM |
521 | /* |
522 | * Let these rates down more difficult. | |
523 | */ | |
536d190d | 524 | if (MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36) |
1748d2de | 525 | TryDownTh += 1; |
88adc104 | 526 | |
da45e3fe | 527 | /* 1 Adjust Rate. */ |
aada7fdd | 528 | if (priv->bTryuping == true) { |
da45e3fe AM |
529 | /* 2 For Test Upgrading mechanism |
530 | * Note: | |
ed2cb4f3 | 531 | * Sometimes the throughput is upon on the capability between the AP and NIC, |
da45e3fe AM |
532 | * thus the low data rate does not improve the performance. |
533 | * We randomly upgrade the data rate and check if the retry rate is improved. | |
534 | */ | |
535 | ||
536 | /* Upgrading rate did not improve the retry rate, fallback to the original rate. */ | |
536d190d | 537 | if ((CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput) { |
da45e3fe | 538 | /*Not necessary raising rate, fall back rate. */ |
88adc104 | 539 | bTryDown = true; |
aada7fdd | 540 | } else { |
88adc104 GKH |
541 | priv->bTryuping = false; |
542 | } | |
aada7fdd | 543 | } else if (CurrSignalStrength > -47 && (CurrRetryRate < 50)) { |
da45e3fe | 544 | /* |
9cf66a95 | 545 | * 2For High Power |
da45e3fe | 546 | * |
da45e3fe AM |
547 | * Return to highest data rate, if signal strength is good enough. |
548 | * SignalStrength threshold(-50dbm) is for RTL8186. | |
549 | * Revise SignalStrength threshold to -51dbm. | |
550 | */ | |
551 | /* Also need to check retry rate for safety, by Bruce, 2007-06-05. */ | |
536d190d | 552 | if (priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate) { |
88adc104 | 553 | bTryUp = true; |
da45e3fe | 554 | /* Upgrade Tx Rate directly. */ |
88adc104 GKH |
555 | priv->TryupingCount += TryUpTh; |
556 | } | |
88adc104 | 557 | |
536d190d | 558 | } else if (CurrTxokCnt > 9 && CurrTxokCnt < 100 && CurrRetryRate >= 600) { |
da45e3fe AM |
559 | /* |
560 | *2 For Serious Retry | |
561 | * | |
562 | * Traffic is not busy but our Tx retry is serious. | |
563 | */ | |
88adc104 | 564 | bTryDown = true; |
da45e3fe | 565 | /* Let Rate Mechanism to degrade tx rate directly. */ |
88adc104 | 566 | priv->TryDownCountLowData += TryDownTh; |
536d190d | 567 | } else if (priv->CurrentOperaRate == 108) { |
da45e3fe AM |
568 | /* 2For 54Mbps */ |
569 | /* Air Link */ | |
536d190d | 570 | if ((CurrRetryRate > 26) && (priv->LastRetryRate > 25)) { |
88adc104 GKH |
571 | bTryDown = true; |
572 | } | |
da45e3fe | 573 | /* Cable Link */ |
536d190d | 574 | else if ((CurrRetryRate > 17) && (priv->LastRetryRate > 16) && (CurrSignalStrength > -72)) { |
88adc104 GKH |
575 | bTryDown = true; |
576 | } | |
577 | ||
da45e3fe | 578 | if (bTryDown && (CurrSignalStrength < -75)) /* cable link */ |
88adc104 | 579 | priv->TryDownCountLowData += TryDownTh; |
9cf66a95 | 580 | } else if (priv->CurrentOperaRate == 96) { |
da45e3fe AM |
581 | /* 2For 48Mbps */ |
582 | /* Air Link */ | |
536d190d | 583 | if (((CurrRetryRate > 48) && (priv->LastRetryRate > 47))) { |
88adc104 | 584 | bTryDown = true; |
da45e3fe AM |
585 | } else if (((CurrRetryRate > 21) && (priv->LastRetryRate > 20)) && (CurrSignalStrength > -74)) { /* Cable Link */ |
586 | /* Down to rate 36Mbps. */ | |
88adc104 | 587 | bTryDown = true; |
536d190d | 588 | } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { |
88adc104 GKH |
589 | bTryDown = true; |
590 | priv->TryDownCountLowData += TryDownTh; | |
da45e3fe | 591 | } else if ((CurrRetryRate < 8) && (priv->LastRetryRate < 8)) { /* TO DO: need to consider (RSSI) */ |
88adc104 GKH |
592 | bTryUp = true; |
593 | } | |
594 | ||
9cf66a95 | 595 | if (bTryDown && (CurrSignalStrength < -75)) { |
88adc104 GKH |
596 | priv->TryDownCountLowData += TryDownTh; |
597 | } | |
536d190d | 598 | } else if (priv->CurrentOperaRate == 72) { |
da45e3fe | 599 | /* 2For 36Mbps */ |
536d190d | 600 | if ((CurrRetryRate > 43) && (priv->LastRetryRate > 41)) { |
da45e3fe | 601 | /* Down to rate 24Mbps. */ |
88adc104 | 602 | bTryDown = true; |
536d190d | 603 | } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { |
88adc104 GKH |
604 | bTryDown = true; |
605 | priv->TryDownCountLowData += TryDownTh; | |
da45e3fe | 606 | } else if ((CurrRetryRate < 15) && (priv->LastRetryRate < 16)) { /* TO DO: need to consider (RSSI) */ |
88adc104 GKH |
607 | bTryUp = true; |
608 | } | |
609 | ||
536d190d | 610 | if (bTryDown && (CurrSignalStrength < -80)) |
88adc104 | 611 | priv->TryDownCountLowData += TryDownTh; |
aada7fdd | 612 | |
536d190d | 613 | } else if (priv->CurrentOperaRate == 48) { |
da45e3fe AM |
614 | /* 2For 24Mbps */ |
615 | /* Air Link */ | |
536d190d | 616 | if (((CurrRetryRate > 63) && (priv->LastRetryRate > 62))) { |
88adc104 | 617 | bTryDown = true; |
da45e3fe | 618 | } else if (((CurrRetryRate > 33) && (priv->LastRetryRate > 32)) && (CurrSignalStrength > -82)) { /* Cable Link */ |
88adc104 | 619 | bTryDown = true; |
9cf66a95 | 620 | } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { |
88adc104 GKH |
621 | bTryDown = true; |
622 | priv->TryDownCountLowData += TryDownTh; | |
da45e3fe | 623 | } else if ((CurrRetryRate < 20) && (priv->LastRetryRate < 21)) { /* TO DO: need to consider (RSSI) */ |
88adc104 GKH |
624 | bTryUp = true; |
625 | } | |
626 | ||
536d190d | 627 | if (bTryDown && (CurrSignalStrength < -82)) |
88adc104 | 628 | priv->TryDownCountLowData += TryDownTh; |
aada7fdd | 629 | |
536d190d | 630 | } else if (priv->CurrentOperaRate == 36) { |
536d190d | 631 | if (((CurrRetryRate > 85) && (priv->LastRetryRate > 86))) { |
88adc104 | 632 | bTryDown = true; |
536d190d | 633 | } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { |
88adc104 GKH |
634 | bTryDown = true; |
635 | priv->TryDownCountLowData += TryDownTh; | |
da45e3fe | 636 | } else if ((CurrRetryRate < 22) && (priv->LastRetryRate < 23)) { /* TO DO: need to consider (RSSI) */ |
88adc104 GKH |
637 | bTryUp = true; |
638 | } | |
536d190d | 639 | } else if (priv->CurrentOperaRate == 22) { |
da45e3fe | 640 | /* 2For 11Mbps */ |
536d190d | 641 | if (CurrRetryRate > 95) { |
88adc104 | 642 | bTryDown = true; |
9cf66a95 | 643 | } else if ((CurrRetryRate < 29) && (priv->LastRetryRate < 30)) { /*TO DO: need to consider (RSSI) */ |
88adc104 | 644 | bTryUp = true; |
88adc104 | 645 | } |
536d190d | 646 | } else if (priv->CurrentOperaRate == 11) { |
da45e3fe | 647 | /* 2For 5.5Mbps */ |
536d190d | 648 | if (CurrRetryRate > 149) { |
88adc104 | 649 | bTryDown = true; |
536d190d | 650 | } else if ((CurrRetryRate < 60) && (priv->LastRetryRate < 65)) { |
88adc104 | 651 | bTryUp = true; |
88adc104 | 652 | } |
536d190d | 653 | } else if (priv->CurrentOperaRate == 4) { |
da45e3fe | 654 | /* 2For 2 Mbps */ |
536d190d | 655 | if ((CurrRetryRate > 99) && (priv->LastRetryRate > 99)) { |
88adc104 | 656 | bTryDown = true; |
536d190d | 657 | } else if ((CurrRetryRate < 65) && (priv->LastRetryRate < 70)) { |
88adc104 GKH |
658 | bTryUp = true; |
659 | } | |
536d190d | 660 | } else if (priv->CurrentOperaRate == 2) { |
da45e3fe | 661 | /* 2For 1 Mbps */ |
536d190d | 662 | if ((CurrRetryRate < 70) && (priv->LastRetryRate < 75)) { |
88adc104 GKH |
663 | bTryUp = true; |
664 | } | |
88adc104 GKH |
665 | } |
666 | ||
536d190d | 667 | if (bTryUp && bTryDown) |
3717013a | 668 | printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n"); |
88adc104 | 669 | |
da45e3fe AM |
670 | /* 1 Test Upgrading Tx Rate |
671 | * Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC. | |
672 | * To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate. | |
9cf66a95 | 673 | */ |
536d190d | 674 | if (!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0) |
aada7fdd | 675 | && priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2) { |
536d190d | 676 | if (jiffies % (CurrRetryRate + 101) == 0) { |
88adc104 GKH |
677 | bTryUp = true; |
678 | priv->bTryuping = true; | |
88adc104 GKH |
679 | } |
680 | } | |
681 | ||
da45e3fe | 682 | /* 1 Rate Mechanism */ |
536d190d | 683 | if (bTryUp) { |
88adc104 GKH |
684 | priv->TryupingCount++; |
685 | priv->TryDownCountLowData = 0; | |
686 | ||
da45e3fe AM |
687 | /* |
688 | * Check more times if we need to upgrade indeed. | |
689 | * Because the largest value of pHalData->TryupingCount is 0xFFFF and | |
690 | * the largest value of pHalData->FailTxRateCount is 0x14, | |
691 | * this condition will be satisfied at most every 2 min. | |
692 | */ | |
88adc104 | 693 | |
536d190d | 694 | if ((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) || |
aada7fdd | 695 | (CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping) { |
88adc104 | 696 | priv->TryupingCount = 0; |
da45e3fe AM |
697 | /* |
698 | * When transferring from CCK to OFDM, DIG is an important issue. | |
699 | */ | |
536d190d | 700 | if (priv->CurrentOperaRate == 22) |
88adc104 GKH |
701 | bUpdateInitialGain = true; |
702 | ||
9cf66a95 | 703 | /* |
da45e3fe | 704 | * The difference in throughput between 48Mbps and 36Mbps is 8M. |
ed2cb4f3 | 705 | * So, we must be careful in this rate scale. Isaiah 2008-02-15. |
da45e3fe | 706 | */ |
536d190d AM |
707 | if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) && |
708 | (priv->FailTxRateCount > 2)) | |
709 | priv->RateAdaptivePeriod = (RATE_ADAPTIVE_TIMER_PERIOD / 2); | |
88adc104 | 710 | |
da45e3fe AM |
711 | /* (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold. */ |
712 | /* (2)If the signal strength is increased, it may be able to upgrade. */ | |
88adc104 GKH |
713 | |
714 | priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); | |
88adc104 | 715 | |
536d190d AM |
716 | if (priv->CurrentOperaRate == 36) { |
717 | priv->bUpdateARFR = true; | |
da45e3fe | 718 | write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */ |
9cf66a95 | 719 | } else if (priv->bUpdateARFR) { |
536d190d | 720 | priv->bUpdateARFR = false; |
da45e3fe | 721 | write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */ |
88adc104 GKH |
722 | } |
723 | ||
da45e3fe | 724 | /* Update Fail Tx rate and count. */ |
536d190d | 725 | if (priv->LastFailTxRate != priv->CurrentOperaRate) { |
88adc104 GKH |
726 | priv->LastFailTxRate = priv->CurrentOperaRate; |
727 | priv->FailTxRateCount = 0; | |
da45e3fe | 728 | priv->LastFailTxRateSS = -200; /* Set lowest power. */ |
88adc104 GKH |
729 | } |
730 | } | |
aada7fdd | 731 | } else { |
536d190d | 732 | if (priv->TryupingCount > 0) |
9cf66a95 | 733 | priv->TryupingCount--; |
88adc104 GKH |
734 | } |
735 | ||
536d190d | 736 | if (bTryDown) { |
88adc104 GKH |
737 | priv->TryDownCountLowData++; |
738 | priv->TryupingCount = 0; | |
aada7fdd | 739 | |
da45e3fe | 740 | /* Check if Tx rate can be degraded or Test trying upgrading should fallback. */ |
536d190d | 741 | if (priv->TryDownCountLowData > TryDownTh || priv->bTryuping) { |
88adc104 GKH |
742 | priv->TryDownCountLowData = 0; |
743 | priv->bTryuping = false; | |
da45e3fe | 744 | /* Update fail information. */ |
536d190d AM |
745 | if (priv->LastFailTxRate == priv->CurrentOperaRate) { |
746 | priv->FailTxRateCount++; | |
da45e3fe | 747 | /* Record the Tx fail rate signal strength. */ |
536d190d | 748 | if (CurrSignalStrength > priv->LastFailTxRateSS) |
88adc104 | 749 | priv->LastFailTxRateSS = CurrSignalStrength; |
aada7fdd | 750 | } else { |
88adc104 GKH |
751 | priv->LastFailTxRate = priv->CurrentOperaRate; |
752 | priv->FailTxRateCount = 1; | |
753 | priv->LastFailTxRateSS = CurrSignalStrength; | |
754 | } | |
755 | priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate); | |
756 | ||
da45e3fe | 757 | /* Reduce chariot training time at weak signal strength situation. SD3 ED demand. */ |
9cf66a95 | 758 | if ((CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72)) { |
88adc104 | 759 | priv->CurrentOperaRate = 72; |
88adc104 GKH |
760 | } |
761 | ||
536d190d AM |
762 | if (priv->CurrentOperaRate == 36) { |
763 | priv->bUpdateARFR = true; | |
da45e3fe | 764 | write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */ |
536d190d AM |
765 | } else if (priv->bUpdateARFR) { |
766 | priv->bUpdateARFR = false; | |
da45e3fe | 767 | write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */ |
88adc104 GKH |
768 | } |
769 | ||
da45e3fe AM |
770 | /* |
771 | * When it is CCK rate, it may need to update initial gain to receive lower power packets. | |
772 | */ | |
536d190d | 773 | if (MgntIsCckRate(priv->CurrentOperaRate)) { |
88adc104 GKH |
774 | bUpdateInitialGain = true; |
775 | } | |
88adc104 | 776 | } |
aada7fdd | 777 | } else { |
536d190d AM |
778 | if (priv->TryDownCountLowData > 0) |
779 | priv->TryDownCountLowData--; | |
88adc104 GKH |
780 | } |
781 | ||
9cf66a95 AR |
782 | /* |
783 | * Keep the Tx fail rate count to equal to 0x15 at most. | |
da45e3fe AM |
784 | * Reduce the fail count at least to 10 sec if tx rate is tending stable. |
785 | */ | |
536d190d | 786 | if (priv->FailTxRateCount >= 0x15 || |
aada7fdd | 787 | (!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6)) { |
536d190d | 788 | priv->FailTxRateCount--; |
88adc104 GKH |
789 | } |
790 | ||
791 | ||
792 | OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; | |
793 | CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; | |
794 | ||
3e837dca | 795 | /* Mac0x9e increase 2 level in 36M~18M situation */ |
536d190d | 796 | if ((priv->CurrentOperaRate < 96) && (priv->CurrentOperaRate > 22)) { |
88adc104 GKH |
797 | u1bCck = read_nic_byte(dev, CCK_TXAGC); |
798 | u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); | |
799 | ||
da45e3fe | 800 | /* case 1: Never enter High power */ |
536d190d AM |
801 | if (u1bCck == CckTxPwrIdx) { |
802 | if (u1bOfdm != (OfdmTxPwrIdx + 2)) { | |
803 | priv->bEnhanceTxPwr = true; | |
9cf66a95 | 804 | u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); |
88adc104 | 805 | write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); |
88adc104 | 806 | } |
536d190d | 807 | } else if (u1bCck < CckTxPwrIdx) { |
da45e3fe | 808 | /* case 2: enter high power */ |
536d190d AM |
809 | if (!priv->bEnhanceTxPwr) { |
810 | priv->bEnhanceTxPwr = true; | |
9cf66a95 | 811 | u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); |
88adc104 | 812 | write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); |
88adc104 GKH |
813 | } |
814 | } | |
da45e3fe | 815 | } else if (priv->bEnhanceTxPwr) { /* 54/48/11/5.5/2/1 */ |
88adc104 GKH |
816 | u1bCck = read_nic_byte(dev, CCK_TXAGC); |
817 | u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); | |
818 | ||
da45e3fe | 819 | /* case 1: Never enter High power */ |
536d190d AM |
820 | if (u1bCck == CckTxPwrIdx) { |
821 | priv->bEnhanceTxPwr = false; | |
1748d2de | 822 | write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); |
88adc104 | 823 | } |
da45e3fe | 824 | /* case 2: enter high power */ |
536d190d AM |
825 | else if (u1bCck < CckTxPwrIdx) { |
826 | priv->bEnhanceTxPwr = false; | |
9cf66a95 | 827 | u1bOfdm = ((u1bOfdm - 2) > 0) ? (u1bOfdm - 2) : 0; |
88adc104 | 828 | write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); |
88adc104 GKH |
829 | } |
830 | } | |
831 | ||
da45e3fe AM |
832 | /* |
833 | * We need update initial gain when we set tx rate "from OFDM to CCK" or | |
834 | * "from CCK to OFDM". | |
835 | */ | |
88adc104 | 836 | SetInitialGain: |
536d190d | 837 | if (bUpdateInitialGain) { |
da45e3fe | 838 | if (MgntIsCckRate(priv->CurrentOperaRate)) { /* CCK */ |
536d190d AM |
839 | if (priv->InitialGain > priv->RegBModeGainStage) { |
840 | priv->InitialGainBackUp = priv->InitialGain; | |
88adc104 | 841 | |
da45e3fe AM |
842 | if (CurrSignalStrength < -85) /* Low power, OFDM [0x17] = 26. */ |
843 | /* SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26. */ | |
88adc104 | 844 | priv->InitialGain = priv->RegBModeGainStage; |
aada7fdd | 845 | |
536d190d | 846 | else if (priv->InitialGain > priv->RegBModeGainStage + 1) |
88adc104 | 847 | priv->InitialGain -= 2; |
aada7fdd | 848 | |
1748d2de | 849 | else |
536d190d | 850 | priv->InitialGain--; |
aada7fdd | 851 | |
9cf66a95 | 852 | printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); |
88adc104 GKH |
853 | UpdateInitialGain(dev); |
854 | } | |
da45e3fe | 855 | } else { /* OFDM */ |
536d190d AM |
856 | if (priv->InitialGain < 4) { |
857 | priv->InitialGainBackUp = priv->InitialGain; | |
88adc104 | 858 | |
536d190d | 859 | priv->InitialGain++; |
9cf66a95 | 860 | printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); |
88adc104 GKH |
861 | UpdateInitialGain(dev); |
862 | } | |
863 | } | |
864 | } | |
865 | ||
da45e3fe | 866 | /* Record the related info */ |
88adc104 GKH |
867 | priv->LastRetryRate = CurrRetryRate; |
868 | priv->LastTxThroughput = TxThroughput; | |
869 | priv->ieee80211->rate = priv->CurrentOperaRate * 5; | |
870 | } | |
0370453f | 871 | |
536d190d | 872 | void rtl8180_rate_adapter(struct work_struct *work) |
88adc104 | 873 | { |
5f546031 | 874 | struct delayed_work *dwork = to_delayed_work(work); |
536d190d | 875 | struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, rate_adapter_wq); |
1748d2de | 876 | struct net_device *dev = ieee->dev; |
1748d2de | 877 | StaRateAdaptive87SE(dev); |
88adc104 GKH |
878 | } |
879 | void timer_rate_adaptive(unsigned long data) | |
880 | { | |
536d190d | 881 | struct r8180_priv *priv = ieee80211_priv((struct net_device *)data); |
536d190d | 882 | if (!priv->up) { |
88adc104 GKH |
883 | return; |
884 | } | |
536d190d | 885 | if ((priv->ieee80211->iw_mode != IW_MODE_MASTER) |
88adc104 | 886 | && (priv->ieee80211->state == IEEE80211_LINKED) && |
536d190d | 887 | (priv->ForcedDataRate == 0)) { |
88adc104 | 888 | queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->rate_adapter_wq); |
88adc104 GKH |
889 | } |
890 | priv->rateadapter_timer.expires = jiffies + MSECS(priv->RateAdaptivePeriod); | |
891 | add_timer(&priv->rateadapter_timer); | |
88adc104 | 892 | } |
3e837dca | 893 | |
536d190d | 894 | void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength) |
88adc104 GKH |
895 | { |
896 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
897 | ||
88adc104 GKH |
898 | priv->AdRxOkCnt++; |
899 | ||
536d190d AM |
900 | if (priv->AdRxSignalStrength != -1) { |
901 | priv->AdRxSignalStrength = ((priv->AdRxSignalStrength * 7) + (SignalStrength * 3)) / 10; | |
da45e3fe | 902 | } else { /* Initialization case. */ |
88adc104 GKH |
903 | priv->AdRxSignalStrength = SignalStrength; |
904 | } | |
9cf66a95 | 905 | |
da45e3fe | 906 | if (priv->LastRxPktAntenna) /* Main antenna. */ |
88adc104 | 907 | priv->AdMainAntennaRxOkCnt++; |
da45e3fe | 908 | else /* Aux antenna. */ |
88adc104 | 909 | priv->AdAuxAntennaRxOkCnt++; |
88adc104 | 910 | } |
3e837dca | 911 | /* Change Antenna Switch. */ |
536d190d | 912 | bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex) |
88adc104 GKH |
913 | { |
914 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
915 | bool bAntennaSwitched = false; | |
916 | ||
536d190d | 917 | switch (u1bAntennaIndex) { |
88adc104 | 918 | case 0: |
8daba6b9 LF |
919 | /* Mac register, main antenna */ |
920 | write_nic_byte(dev, ANTSEL, 0x03); | |
921 | /* base band */ | |
922 | write_phy_cck(dev, 0x11, 0x9b); /* Config CCK RX antenna. */ | |
923 | write_phy_ofdm(dev, 0x0d, 0x5c); /* Config OFDM RX antenna. */ | |
88adc104 | 924 | |
8daba6b9 | 925 | bAntennaSwitched = true; |
88adc104 GKH |
926 | break; |
927 | ||
928 | case 1: | |
8daba6b9 LF |
929 | /* Mac register, aux antenna */ |
930 | write_nic_byte(dev, ANTSEL, 0x00); | |
931 | /* base band */ | |
932 | write_phy_cck(dev, 0x11, 0xbb); /* Config CCK RX antenna. */ | |
933 | write_phy_ofdm(dev, 0x0d, 0x54); /* Config OFDM RX antenna. */ | |
934 | ||
935 | bAntennaSwitched = true; | |
936 | ||
88adc104 GKH |
937 | break; |
938 | ||
939 | default: | |
bbc9a991 | 940 | printk("SetAntenna8185: unknown u1bAntennaIndex(%d)\n", u1bAntennaIndex); |
88adc104 GKH |
941 | break; |
942 | } | |
943 | ||
9cf66a95 | 944 | if (bAntennaSwitched) |
88adc104 | 945 | priv->CurrAntennaIndex = u1bAntennaIndex; |
88adc104 | 946 | |
88adc104 GKH |
947 | return bAntennaSwitched; |
948 | } | |
3e837dca | 949 | /* Toggle Antenna switch. */ |
536d190d | 950 | bool SwitchAntenna(struct net_device *dev) |
88adc104 GKH |
951 | { |
952 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
953 | ||
954 | bool bResult; | |
955 | ||
536d190d | 956 | if (priv->CurrAntennaIndex == 0) { |
1748d2de | 957 | bResult = SetAntenna8185(dev, 1); |
aada7fdd | 958 | } else { |
1748d2de | 959 | bResult = SetAntenna8185(dev, 0); |
88adc104 GKH |
960 | } |
961 | ||
962 | return bResult; | |
963 | } | |
da45e3fe | 964 | /* |
3e837dca AM |
965 | * Engine of SW Antenna Diversity mechanism. |
966 | * Since 8187 has no Tx part information, | |
967 | * this implementation is only dependend on Rx part information. | |
da45e3fe | 968 | */ |
536d190d | 969 | void SwAntennaDiversity(struct net_device *dev) |
88adc104 GKH |
970 | { |
971 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
536d190d | 972 | bool bSwCheckSS = false; |
536d190d | 973 | if (bSwCheckSS) { |
88adc104 GKH |
974 | priv->AdTickCount++; |
975 | ||
976 | printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n", | |
977 | priv->AdTickCount, priv->AdCheckPeriod); | |
978 | printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n", | |
979 | priv->AdRxSignalStrength, priv->AdRxSsThreshold); | |
980 | } | |
88adc104 | 981 | |
da45e3fe | 982 | /* Case 1. No Link. */ |
536d190d | 983 | if (priv->ieee80211->state != IEEE80211_LINKED) { |
88adc104 | 984 | priv->bAdSwitchedChecking = false; |
da45e3fe | 985 | /* I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko.. */ |
88adc104 | 986 | SwitchAntenna(dev); |
aada7fdd | 987 | |
da45e3fe | 988 | /* Case 2. Linked but no packet receive.d */ |
536d190d | 989 | } else if (priv->AdRxOkCnt == 0) { |
88adc104 GKH |
990 | priv->bAdSwitchedChecking = false; |
991 | SwitchAntenna(dev); | |
aada7fdd | 992 | |
da45e3fe | 993 | /* Case 3. Evaluate last antenna switch action and undo it if necessary. */ |
536d190d | 994 | } else if (priv->bAdSwitchedChecking == true) { |
88adc104 GKH |
995 | priv->bAdSwitchedChecking = false; |
996 | ||
da45e3fe | 997 | /* Adjust Rx signal strength threshold. */ |
88adc104 GKH |
998 | priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2; |
999 | ||
1000 | priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? | |
9cf66a95 AR |
1001 | priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold; |
1002 | if (priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) { | |
da45e3fe | 1003 | /* Rx signal strength is not improved after we swtiched antenna. => Swich back. */ |
da45e3fe | 1004 | /* Increase Antenna Diversity checking period due to bad decision. */ |
88adc104 | 1005 | priv->AdCheckPeriod *= 2; |
da45e3fe | 1006 | /* Increase Antenna Diversity checking period. */ |
536d190d | 1007 | if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod) |
88adc104 GKH |
1008 | priv->AdCheckPeriod = priv->AdMaxCheckPeriod; |
1009 | ||
ed2cb4f3 | 1010 | /* Wrong decision => switch back. */ |
88adc104 | 1011 | SwitchAntenna(dev); |
1748d2de | 1012 | } else { |
da45e3fe | 1013 | /* Rx Signal Strength is improved. */ |
88adc104 | 1014 | |
da45e3fe | 1015 | /* Reset Antenna Diversity checking period to its min value. */ |
88adc104 GKH |
1016 | priv->AdCheckPeriod = priv->AdMinCheckPeriod; |
1017 | } | |
1018 | ||
88adc104 | 1019 | } |
da45e3fe AM |
1020 | /* Case 4. Evaluate if we shall switch antenna now. */ |
1021 | /* Cause Table Speed is very fast in TRC Dell Lab, we check it every time. */ | |
3e837dca | 1022 | else { |
88adc104 GKH |
1023 | priv->AdTickCount = 0; |
1024 | ||
da45e3fe AM |
1025 | /* |
1026 | * <Roger_Notes> We evaluate RxOk counts for each antenna first and than | |
1027 | * evaluate signal strength. | |
1028 | * The following operation can overcome the disability of CCA on both two antennas | |
1029 | * When signal strength was extremely low or high. | |
1030 | * 2008.01.30. | |
1031 | */ | |
1032 | ||
1033 | /* | |
1034 | * Evaluate RxOk count from each antenna if we shall switch default antenna now. | |
da45e3fe | 1035 | */ |
536d190d | 1036 | if ((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt) |
aada7fdd | 1037 | && (priv->CurrAntennaIndex == 0)) { |
da45e3fe | 1038 | /* We set Main antenna as default but RxOk count was less than Aux ones. */ |
88adc104 | 1039 | |
da45e3fe | 1040 | /* Switch to Aux antenna. */ |
88adc104 GKH |
1041 | SwitchAntenna(dev); |
1042 | priv->bHWAdSwitched = true; | |
536d190d | 1043 | } else if ((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt) |
aada7fdd | 1044 | && (priv->CurrAntennaIndex == 1)) { |
da45e3fe | 1045 | /* We set Aux antenna as default but RxOk count was less than Main ones. */ |
88adc104 | 1046 | |
da45e3fe | 1047 | /* Switch to Main antenna. */ |
88adc104 GKH |
1048 | SwitchAntenna(dev); |
1049 | priv->bHWAdSwitched = true; | |
aada7fdd | 1050 | } else { |
da45e3fe | 1051 | /* Default antenna is better. */ |
88adc104 | 1052 | |
da45e3fe | 1053 | /* Still need to check current signal strength. */ |
88adc104 GKH |
1054 | priv->bHWAdSwitched = false; |
1055 | } | |
da45e3fe AM |
1056 | /* |
1057 | * <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna | |
ed2cb4f3 | 1058 | * didn't change by HW evaluation. |
da45e3fe AM |
1059 | * 2008.02.27. |
1060 | * | |
1061 | * [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05 | |
1062 | * For example, Throughput of aux is better than main antenna(about 10M v.s 2M), | |
1063 | * but AdRxSignalStrength is less than main. | |
1064 | * Our guess is that main antenna have lower throughput and get many change | |
1065 | * to receive more CCK packets(ex.Beacon) which have stronger SignalStrength. | |
1066 | */ | |
536d190d | 1067 | if ((!priv->bHWAdSwitched) && (bSwCheckSS)) { |
da45e3fe | 1068 | /* Evaluate Rx signal strength if we shall switch antenna now. */ |
536d190d | 1069 | if (priv->AdRxSignalStrength < priv->AdRxSsThreshold) { |
da45e3fe | 1070 | /* Rx signal strength is weak => Switch Antenna. */ |
1748d2de AM |
1071 | priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength; |
1072 | priv->bAdSwitchedChecking = true; | |
88adc104 | 1073 | |
1748d2de AM |
1074 | SwitchAntenna(dev); |
1075 | } else { | |
da45e3fe | 1076 | /* Rx signal strength is OK. */ |
1748d2de | 1077 | priv->bAdSwitchedChecking = false; |
da45e3fe AM |
1078 | /* Increase Rx signal strength threshold if necessary. */ |
1079 | if ((priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && /* Signal is much stronger than current threshold */ | |
1080 | priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) { /* Current threhold is not yet reach upper limit. */ | |
aada7fdd | 1081 | |
1748d2de AM |
1082 | priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2; |
1083 | priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? | |
9cf66a95 | 1084 | priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold;/* +by amy 080312 */ |
1748d2de | 1085 | } |
88adc104 | 1086 | |
da45e3fe | 1087 | /* Reduce Antenna Diversity checking period if possible. */ |
536d190d | 1088 | if (priv->AdCheckPeriod > priv->AdMinCheckPeriod) |
1748d2de AM |
1089 | priv->AdCheckPeriod /= 2; |
1090 | } | |
88adc104 GKH |
1091 | } |
1092 | } | |
da45e3fe | 1093 | /* Reset antenna diversity Rx related statistics. */ |
88adc104 GKH |
1094 | priv->AdRxOkCnt = 0; |
1095 | priv->AdMainAntennaRxOkCnt = 0; | |
1096 | priv->AdAuxAntennaRxOkCnt = 0; | |
88adc104 GKH |
1097 | } |
1098 | ||
ed2cb4f3 | 1099 | /* Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */ |
536d190d | 1100 | bool CheckTxPwrTracking(struct net_device *dev) |
88adc104 GKH |
1101 | { |
1102 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
1103 | ||
536d190d | 1104 | if (!priv->bTxPowerTrack) |
88adc104 | 1105 | return false; |
88adc104 | 1106 | |
da45e3fe | 1107 | /* if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah */ |
536d190d | 1108 | if (priv->bToUpdateTxPwr) |
88adc104 | 1109 | return false; |
88adc104 GKH |
1110 | |
1111 | return true; | |
1112 | } | |
1113 | ||
1114 | ||
3e837dca | 1115 | /* Timer callback function of SW Antenna Diversity. */ |
536d190d | 1116 | void SwAntennaDiversityTimerCallback(struct net_device *dev) |
88adc104 GKH |
1117 | { |
1118 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | |
c0cfe01f | 1119 | enum rt_rf_power_state rtState; |
88adc104 | 1120 | |
3e837dca | 1121 | /* We do NOT need to switch antenna while RF is off. */ |
88adc104 | 1122 | rtState = priv->eRFPowerState; |
aada7fdd | 1123 | do { |
c0cfe01f | 1124 | if (rtState == RF_OFF) { |
88adc104 | 1125 | break; |
c0cfe01f | 1126 | } else if (rtState == RF_SLEEP) { |
da45e3fe | 1127 | /* Don't access BB/RF under Disable PLL situation. */ |
88adc104 GKH |
1128 | break; |
1129 | } | |
1130 | SwAntennaDiversity(dev); | |
1131 | ||
536d190d | 1132 | } while (false); |
88adc104 | 1133 | |
536d190d | 1134 | if (priv->up) { |
88adc104 GKH |
1135 | priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD); |
1136 | add_timer(&priv->SwAntennaDiversityTimer); | |
1137 | } | |
88adc104 GKH |
1138 | } |
1139 |