aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/lo.c
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-04-20 10:03:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-07 15:02:12 -0400
commitf5eda47f45e90dfa38e25d569b9ac84ba94f8301 (patch)
tree5f806ae4729696cebef0bef0c261c6353b18045a /drivers/net/wireless/b43/lo.c
parent2afc49015db927fea7bc6ca33c0a60bf5d7c2c5f (diff)
b43: Rewrite LO calibration algorithm
This patch distributes the Local Oscillator calibration bursts over time, so that calibration only happens when it's actually needed. Currently we periodically perform a recalibration of the whole table. The table is huge and this takes lots of time. Additionally only small bits of the table are actually needed at a given time. So instead of maintaining a huge table with all possible calibration values, we create dynamic calibration settings that a) We only calibrate when they are actually needed. b) Are cached for some time until they expire. So a recalibration might happen if we need a calibration setting that's not cached, or if the active calibration setting expires. Currently the expire timeout is set to 30 seconds. We may raise that in future. This patch reduces overall memory consumption by nuking the huge static calibration tables. This patch has been tested on several 4306, 4311 and 4318 flavours. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/lo.c')
-rw-r--r--drivers/net/wireless/b43/lo.c721
1 files changed, 249 insertions, 472 deletions
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index d890f366a23b..4edee6da2b8b 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -36,10 +36,22 @@
36#include <linux/sched.h> 36#include <linux/sched.h>
37 37
38 38
39/* Define to 1 to always calibrate all possible LO control pairs. 39static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo,
40 * This is a workaround until we fix the partial LO calibration optimization. */ 40 const struct b43_bbatt *bbatt,
41#define B43_CALIB_ALL_LOCTLS 1 41 const struct b43_rfatt *rfatt)
42{
43 struct b43_lo_calib *c;
44
45 list_for_each_entry(c, &lo->calib_list, list) {
46 if (!b43_compare_bbatt(&c->bbatt, bbatt))
47 continue;
48 if (!b43_compare_rfatt(&c->rfatt, rfatt))
49 continue;
50 return c;
51 }
42 52
53 return NULL;
54}
43 55
44/* Write the LocalOscillator Control (adjust) value-pair. */ 56/* Write the LocalOscillator Control (adjust) value-pair. */
45static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) 57static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
@@ -64,183 +76,6 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
64 b43_phy_write(dev, reg, value); 76 b43_phy_write(dev, reg, value);
65} 77}
66 78
67static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
68 const struct b43_bbatt *bbatt,
69 struct b43_wldev *dev)
70{
71 int err = 0;
72
73 /* Check the attenuation values against the LO control array sizes. */
74 if (unlikely(rfatt->att >= B43_NR_RF)) {
75 b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
76 err = -EINVAL;
77 }
78 if (unlikely(bbatt->att >= B43_NR_BB)) {
79 b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
80 err = -EINVAL;
81 }
82
83 return err;
84}
85
86#if !B43_CALIB_ALL_LOCTLS
87static
88struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
89 const struct b43_rfatt *rfatt,
90 const struct b43_bbatt *bbatt)
91{
92 struct b43_phy *phy = &dev->phy;
93 struct b43_txpower_lo_control *lo = phy->lo_control;
94
95 if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
96 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
97 return &(lo->no_padmix[bbatt->att][rfatt->att]);
98}
99#endif /* !B43_CALIB_ALL_LOCTLS */
100
101struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
102 const struct b43_rfatt *rfatt,
103 const struct b43_bbatt *bbatt)
104{
105 struct b43_phy *phy = &dev->phy;
106 struct b43_txpower_lo_control *lo = phy->lo_control;
107
108 if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
109 return &(lo->no_padmix[0][0]); /* Just prevent a crash */
110 if (rfatt->with_padmix)
111 return &(lo->with_padmix[bbatt->att][rfatt->att]);
112 return &(lo->no_padmix[bbatt->att][rfatt->att]);
113}
114
115/* Call a function for every possible LO control value-pair. */
116static void b43_call_for_each_loctl(struct b43_wldev *dev,
117 void (*func) (struct b43_wldev *,
118 struct b43_loctl *))
119{
120 struct b43_phy *phy = &dev->phy;
121 struct b43_txpower_lo_control *ctl = phy->lo_control;
122 int i, j;
123
124 for (i = 0; i < B43_NR_BB; i++) {
125 for (j = 0; j < B43_NR_RF; j++)
126 func(dev, &(ctl->with_padmix[i][j]));
127 }
128 for (i = 0; i < B43_NR_BB; i++) {
129 for (j = 0; j < B43_NR_RF; j++)
130 func(dev, &(ctl->no_padmix[i][j]));
131 }
132}
133
134static u16 lo_b_r15_loop(struct b43_wldev *dev)
135{
136 int i;
137 u16 ret = 0;
138
139 for (i = 0; i < 10; i++) {
140 b43_phy_write(dev, 0x0015, 0xAFA0);
141 udelay(1);
142 b43_phy_write(dev, 0x0015, 0xEFA0);
143 udelay(10);
144 b43_phy_write(dev, 0x0015, 0xFFA0);
145 udelay(40);
146 ret += b43_phy_read(dev, 0x002C);
147 }
148
149 return ret;
150}
151
152void b43_lo_b_measure(struct b43_wldev *dev)
153{
154 struct b43_phy *phy = &dev->phy;
155 u16 regstack[12] = { 0 };
156 u16 mls;
157 u16 fval;
158 int i, j;
159
160 regstack[0] = b43_phy_read(dev, 0x0015);
161 regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
162
163 if (phy->radio_ver == 0x2053) {
164 regstack[2] = b43_phy_read(dev, 0x000A);
165 regstack[3] = b43_phy_read(dev, 0x002A);
166 regstack[4] = b43_phy_read(dev, 0x0035);
167 regstack[5] = b43_phy_read(dev, 0x0003);
168 regstack[6] = b43_phy_read(dev, 0x0001);
169 regstack[7] = b43_phy_read(dev, 0x0030);
170
171 regstack[8] = b43_radio_read16(dev, 0x0043);
172 regstack[9] = b43_radio_read16(dev, 0x007A);
173 regstack[10] = b43_read16(dev, 0x03EC);
174 regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
175
176 b43_phy_write(dev, 0x0030, 0x00FF);
177 b43_write16(dev, 0x03EC, 0x3F3F);
178 b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
179 b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
180 }
181 b43_phy_write(dev, 0x0015, 0xB000);
182 b43_phy_write(dev, 0x002B, 0x0004);
183
184 if (phy->radio_ver == 0x2053) {
185 b43_phy_write(dev, 0x002B, 0x0203);
186 b43_phy_write(dev, 0x002A, 0x08A3);
187 }
188
189 phy->minlowsig[0] = 0xFFFF;
190
191 for (i = 0; i < 4; i++) {
192 b43_radio_write16(dev, 0x0052, regstack[1] | i);
193 lo_b_r15_loop(dev);
194 }
195 for (i = 0; i < 10; i++) {
196 b43_radio_write16(dev, 0x0052, regstack[1] | i);
197 mls = lo_b_r15_loop(dev) / 10;
198 if (mls < phy->minlowsig[0]) {
199 phy->minlowsig[0] = mls;
200 phy->minlowsigpos[0] = i;
201 }
202 }
203 b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
204
205 phy->minlowsig[1] = 0xFFFF;
206
207 for (i = -4; i < 5; i += 2) {
208 for (j = -4; j < 5; j += 2) {
209 if (j < 0)
210 fval = (0x0100 * i) + j + 0x0100;
211 else
212 fval = (0x0100 * i) + j;
213 b43_phy_write(dev, 0x002F, fval);
214 mls = lo_b_r15_loop(dev) / 10;
215 if (mls < phy->minlowsig[1]) {
216 phy->minlowsig[1] = mls;
217 phy->minlowsigpos[1] = fval;
218 }
219 }
220 }
221 phy->minlowsigpos[1] += 0x0101;
222
223 b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
224 if (phy->radio_ver == 0x2053) {
225 b43_phy_write(dev, 0x000A, regstack[2]);
226 b43_phy_write(dev, 0x002A, regstack[3]);
227 b43_phy_write(dev, 0x0035, regstack[4]);
228 b43_phy_write(dev, 0x0003, regstack[5]);
229 b43_phy_write(dev, 0x0001, regstack[6]);
230 b43_phy_write(dev, 0x0030, regstack[7]);
231
232 b43_radio_write16(dev, 0x0043, regstack[8]);
233 b43_radio_write16(dev, 0x007A, regstack[9]);
234
235 b43_radio_write16(dev, 0x0052,
236 (b43_radio_read16(dev, 0x0052) & 0x000F)
237 | regstack[11]);
238
239 b43_write16(dev, 0x03EC, regstack[10]);
240 }
241 b43_phy_write(dev, 0x0015, regstack[0]);
242}
243
244static u16 lo_measure_feedthrough(struct b43_wldev *dev, 79static u16 lo_measure_feedthrough(struct b43_wldev *dev,
245 u16 lna, u16 pga, u16 trsw_rx) 80 u16 lna, u16 pga, u16 trsw_rx)
246{ 81{
@@ -438,48 +273,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
438 b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) 273 b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
439 & 0xFFF0); /* TX bias == 0 */ 274 & 0xFFF0); /* TX bias == 0 */
440 } 275 }
276 lo->txctl_measured_time = jiffies;
441} 277}
442 278
443static void lo_read_power_vector(struct b43_wldev *dev) 279static void lo_read_power_vector(struct b43_wldev *dev)
444{ 280{
445 struct b43_phy *phy = &dev->phy; 281 struct b43_phy *phy = &dev->phy;
446 struct b43_txpower_lo_control *lo = phy->lo_control; 282 struct b43_txpower_lo_control *lo = phy->lo_control;
447 u16 i; 283 int i;
448 u64 tmp; 284 u64 tmp;
449 u64 power_vector = 0; 285 u64 power_vector = 0;
450 int rf_offset, bb_offset;
451 struct b43_loctl *loctl;
452 286
453 for (i = 0; i < 8; i += 2) { 287 for (i = 0; i < 8; i += 2) {
454 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); 288 tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
455 /* Clear the top byte. We get holes in the bitmap... */
456 tmp &= 0xFF;
457 power_vector |= (tmp << (i * 8)); 289 power_vector |= (tmp << (i * 8));
458 /* Clear the vector on the device. */ 290 /* Clear the vector on the device. */
459 b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); 291 b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
460 } 292 }
461
462 if (power_vector) 293 if (power_vector)
463 lo->power_vector = power_vector; 294 lo->power_vector = power_vector;
464 power_vector = lo->power_vector; 295 lo->pwr_vec_read_time = jiffies;
465
466 for (i = 0; i < 64; i++) {
467 if (power_vector & ((u64) 1ULL << i)) {
468 /* Now figure out which b43_loctl corresponds
469 * to this bit.
470 */
471 rf_offset = i / lo->rfatt_list.len;
472 bb_offset = i % lo->rfatt_list.len; //FIXME?
473 loctl =
474 b43_get_lo_g_ctl(dev,
475 &lo->rfatt_list.list[rf_offset],
476 &lo->bbatt_list.list[bb_offset]);
477 /* And mark it as "used", as the device told us
478 * through the bitmap it is using it.
479 */
480 loctl->used = 1;
481 }
482 }
483} 296}
484 297
485/* 802.11/LO/GPHY/MeasuringGains */ 298/* 802.11/LO/GPHY/MeasuringGains */
@@ -609,8 +422,6 @@ static void lo_measure_setup(struct b43_wldev *dev,
609 b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); 422 b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
610 b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); 423 b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
611 } 424 }
612 if (!lo->rebuild && b43_has_hardware_pctl(phy))
613 lo_read_power_vector(dev);
614 if (phy->rev >= 2) { 425 if (phy->rev >= 2) {
615 sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); 426 sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
616 sav->phy_analogoverval = 427 sav->phy_analogoverval =
@@ -691,8 +502,12 @@ static void lo_measure_setup(struct b43_wldev *dev,
691 b43_radio_read16(dev, 0x51); /* dummy read */ 502 b43_radio_read16(dev, 0x51); /* dummy read */
692 if (phy->type == B43_PHYTYPE_G) 503 if (phy->type == B43_PHYTYPE_G)
693 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); 504 b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
694 if (lo->rebuild) 505
506 /* Re-measure the txctl values, if needed. */
507 if (time_before(lo->txctl_measured_time,
508 jiffies - B43_LO_TXCTL_EXPIRE))
695 lo_measure_txctl_values(dev); 509 lo_measure_txctl_values(dev);
510
696 if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { 511 if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
697 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); 512 b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
698 } else { 513 } else {
@@ -707,7 +522,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
707 struct lo_g_saved_values *sav) 522 struct lo_g_saved_values *sav)
708{ 523{
709 struct b43_phy *phy = &dev->phy; 524 struct b43_phy *phy = &dev->phy;
710 struct b43_txpower_lo_control *lo = phy->lo_control;
711 u16 tmp; 525 u16 tmp;
712 526
713 if (phy->rev >= 2) { 527 if (phy->rev >= 2) {
@@ -722,14 +536,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
722 tmp = (phy->pga_gain | 0xEFA0); 536 tmp = (phy->pga_gain | 0xEFA0);
723 b43_phy_write(dev, B43_PHY_PGACTL, tmp); 537 b43_phy_write(dev, B43_PHY_PGACTL, tmp);
724 } 538 }
725 if (b43_has_hardware_pctl(phy)) {
726 b43_gphy_dc_lt_init(dev);
727 } else {
728 if (lo->rebuild)
729 b43_lo_g_adjust_to(dev, 3, 2, 0);
730 else
731 b43_lo_g_adjust(dev);
732 }
733 if (phy->type == B43_PHYTYPE_G) { 539 if (phy->type == B43_PHYTYPE_G) {
734 if (phy->rev >= 3) 540 if (phy->rev >= 3)
735 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); 541 b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
@@ -793,7 +599,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
793 struct b43_lo_g_statemachine *d) 599 struct b43_lo_g_statemachine *d)
794{ 600{
795 struct b43_phy *phy = &dev->phy; 601 struct b43_phy *phy = &dev->phy;
796 struct b43_txpower_lo_control *lo = phy->lo_control;
797 struct b43_loctl test_loctl; 602 struct b43_loctl test_loctl;
798 struct b43_loctl orig_loctl; 603 struct b43_loctl orig_loctl;
799 struct b43_loctl prev_loctl = { 604 struct b43_loctl prev_loctl = {
@@ -852,7 +657,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
852 found_lower = 1; 657 found_lower = 1;
853 d->lowest_feedth = feedth; 658 d->lowest_feedth = feedth;
854 if ((d->nr_measured < 2) && 659 if ((d->nr_measured < 2) &&
855 (!has_loopback_gain(phy) || lo->rebuild)) 660 !has_loopback_gain(phy))
856 break; 661 break;
857 } 662 }
858 } 663 }
@@ -874,7 +679,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
874 int *max_rx_gain) 679 int *max_rx_gain)
875{ 680{
876 struct b43_phy *phy = &dev->phy; 681 struct b43_phy *phy = &dev->phy;
877 struct b43_txpower_lo_control *lo = phy->lo_control;
878 struct b43_lo_g_statemachine d; 682 struct b43_lo_g_statemachine d;
879 u16 feedth; 683 u16 feedth;
880 int found_lower; 684 int found_lower;
@@ -883,18 +687,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
883 687
884 d.nr_measured = 0; 688 d.nr_measured = 0;
885 d.state_val_multiplier = 1; 689 d.state_val_multiplier = 1;
886 if (has_loopback_gain(phy) && !lo->rebuild) 690 if (has_loopback_gain(phy))
887 d.state_val_multiplier = 3; 691 d.state_val_multiplier = 3;
888 692
889 memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); 693 memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
890 if (has_loopback_gain(phy) && lo->rebuild) 694 if (has_loopback_gain(phy))
891 max_repeat = 4; 695 max_repeat = 4;
892 do { 696 do {
893 b43_lo_write(dev, &d.min_loctl); 697 b43_lo_write(dev, &d.min_loctl);
894 feedth = lo_measure_feedthrough(dev, phy->lna_gain, 698 feedth = lo_measure_feedthrough(dev, phy->lna_gain,
895 phy->pga_gain, 699 phy->pga_gain,
896 phy->trsw_rx_gain); 700 phy->trsw_rx_gain);
897 if (!lo->rebuild && feedth < 0x258) { 701 if (feedth < 0x258) {
898 if (feedth >= 0x12C) 702 if (feedth >= 0x12C)
899 *max_rx_gain += 6; 703 *max_rx_gain += 6;
900 else 704 else
@@ -944,278 +748,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
944 } while (++repeat_cnt < max_repeat); 748 } while (++repeat_cnt < max_repeat);
945} 749}
946 750
947#if B43_CALIB_ALL_LOCTLS 751static
948static const struct b43_rfatt b43_full_rfatt_list_items[] = { 752struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
949 { .att = 0, .with_padmix = 0, }, 753 const struct b43_bbatt *bbatt,
950 { .att = 1, .with_padmix = 0, }, 754 const struct b43_rfatt *rfatt)
951 { .att = 2, .with_padmix = 0, },
952 { .att = 3, .with_padmix = 0, },
953 { .att = 4, .with_padmix = 0, },
954 { .att = 5, .with_padmix = 0, },
955 { .att = 6, .with_padmix = 0, },
956 { .att = 7, .with_padmix = 0, },
957 { .att = 8, .with_padmix = 0, },
958 { .att = 9, .with_padmix = 0, },
959 { .att = 10, .with_padmix = 0, },
960 { .att = 11, .with_padmix = 0, },
961 { .att = 12, .with_padmix = 0, },
962 { .att = 13, .with_padmix = 0, },
963 { .att = 14, .with_padmix = 0, },
964 { .att = 15, .with_padmix = 0, },
965 { .att = 0, .with_padmix = 1, },
966 { .att = 1, .with_padmix = 1, },
967 { .att = 2, .with_padmix = 1, },
968 { .att = 3, .with_padmix = 1, },
969 { .att = 4, .with_padmix = 1, },
970 { .att = 5, .with_padmix = 1, },
971 { .att = 6, .with_padmix = 1, },
972 { .att = 7, .with_padmix = 1, },
973 { .att = 8, .with_padmix = 1, },
974 { .att = 9, .with_padmix = 1, },
975 { .att = 10, .with_padmix = 1, },
976 { .att = 11, .with_padmix = 1, },
977 { .att = 12, .with_padmix = 1, },
978 { .att = 13, .with_padmix = 1, },
979 { .att = 14, .with_padmix = 1, },
980 { .att = 15, .with_padmix = 1, },
981};
982static const struct b43_rfatt_list b43_full_rfatt_list = {
983 .list = b43_full_rfatt_list_items,
984 .len = ARRAY_SIZE(b43_full_rfatt_list_items),
985};
986
987static const struct b43_bbatt b43_full_bbatt_list_items[] = {
988 { .att = 0, },
989 { .att = 1, },
990 { .att = 2, },
991 { .att = 3, },
992 { .att = 4, },
993 { .att = 5, },
994 { .att = 6, },
995 { .att = 7, },
996 { .att = 8, },
997 { .att = 9, },
998 { .att = 10, },
999 { .att = 11, },
1000};
1001static const struct b43_bbatt_list b43_full_bbatt_list = {
1002 .list = b43_full_bbatt_list_items,
1003 .len = ARRAY_SIZE(b43_full_bbatt_list_items),
1004};
1005#endif /* B43_CALIB_ALL_LOCTLS */
1006
1007static void lo_measure(struct b43_wldev *dev)
1008{ 755{
1009 struct b43_phy *phy = &dev->phy; 756 struct b43_phy *phy = &dev->phy;
1010 struct b43_txpower_lo_control *lo = phy->lo_control;
1011 struct b43_loctl loctl = { 757 struct b43_loctl loctl = {
1012 .i = 0, 758 .i = 0,
1013 .q = 0, 759 .q = 0,
1014 }; 760 };
1015 struct b43_loctl *ploctl;
1016 int max_rx_gain; 761 int max_rx_gain;
1017 int rfidx, bbidx; 762 struct b43_lo_calib *cal;
1018 const struct b43_bbatt_list *bbatt_list; 763 struct lo_g_saved_values uninitialized_var(saved_regs);
1019 const struct b43_rfatt_list *rfatt_list;
1020
1021 /* Values from the "TXCTL Register and Value Table" */ 764 /* Values from the "TXCTL Register and Value Table" */
1022 u16 txctl_reg; 765 u16 txctl_reg;
1023 u16 txctl_value; 766 u16 txctl_value;
1024 u16 pad_mix_gain; 767 u16 pad_mix_gain;
1025 768
1026 bbatt_list = &lo->bbatt_list; 769 saved_regs.old_channel = phy->channel;
1027 rfatt_list = &lo->rfatt_list; 770 b43_mac_suspend(dev);
1028#if B43_CALIB_ALL_LOCTLS 771 lo_measure_setup(dev, &saved_regs);
1029 bbatt_list = &b43_full_bbatt_list;
1030 rfatt_list = &b43_full_rfatt_list;
1031#endif
1032 772
1033 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); 773 txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
1034 774
1035 for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { 775 b43_radio_write16(dev, 0x43,
1036 776 (b43_radio_read16(dev, 0x43) & 0xFFF0)
1037 b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) 777 | rfatt->att);
1038 & 0xFFF0) | 778 b43_radio_write16(dev, txctl_reg,
1039 rfatt_list->list[rfidx].att); 779 (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
1040 b43_radio_write16(dev, txctl_reg, 780 | (rfatt->with_padmix) ? txctl_value : 0);
1041 (b43_radio_read16(dev, txctl_reg)
1042 & ~txctl_value)
1043 | (rfatt_list->list[rfidx].with_padmix ?
1044 txctl_value : 0));
1045
1046 for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
1047 if (lo->rebuild) {
1048#if B43_CALIB_ALL_LOCTLS
1049 ploctl = b43_get_lo_g_ctl(dev,
1050 &rfatt_list->list[rfidx],
1051 &bbatt_list->list[bbidx]);
1052#else
1053 ploctl = b43_get_lo_g_ctl_nopadmix(dev,
1054 &rfatt_list->
1055 list[rfidx],
1056 &bbatt_list->
1057 list[bbidx]);
1058#endif
1059 } else {
1060 ploctl = b43_get_lo_g_ctl(dev,
1061 &rfatt_list->list[rfidx],
1062 &bbatt_list->list[bbidx]);
1063 if (!ploctl->used)
1064 continue;
1065 }
1066 memcpy(&loctl, ploctl, sizeof(loctl));
1067 loctl.i = 0;
1068 loctl.q = 0;
1069
1070 max_rx_gain = rfatt_list->list[rfidx].att * 2;
1071 max_rx_gain += bbatt_list->list[bbidx].att / 2;
1072 if (rfatt_list->list[rfidx].with_padmix)
1073 max_rx_gain -= pad_mix_gain;
1074 if (has_loopback_gain(phy))
1075 max_rx_gain += phy->max_lb_gain;
1076 lo_measure_gain_values(dev, max_rx_gain,
1077 has_loopback_gain(phy));
1078
1079 b43_phy_set_baseband_attenuation(dev,
1080 bbatt_list->list[bbidx].att);
1081 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
1082 if (phy->type == B43_PHYTYPE_B) {
1083 loctl.i++;
1084 loctl.q++;
1085 }
1086 b43_loctl_set_calibrated(&loctl, 1);
1087 memcpy(ploctl, &loctl, sizeof(loctl));
1088 }
1089 }
1090}
1091
1092#if B43_DEBUG
1093static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
1094{
1095 const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
1096 int i = control->i;
1097 int q = control->q;
1098 781
1099 if (b43_loctl_is_calibrated(control)) { 782 max_rx_gain = rfatt->att * 2;
1100 if ((abs(i) > 16) || (abs(q) > 16)) 783 max_rx_gain += bbatt->att / 2;
1101 goto error; 784 if (rfatt->with_padmix)
1102 } else { 785 max_rx_gain -= pad_mix_gain;
1103 if (control->used) 786 if (has_loopback_gain(phy))
1104 goto error; 787 max_rx_gain += phy->max_lb_gain;
1105 if (dev->phy.lo_control->rebuild) { 788 lo_measure_gain_values(dev, max_rx_gain,
1106 control->i = 0; 789 has_loopback_gain(phy));
1107 control->q = 0; 790
1108 if ((i != B43_LOCTL_POISON) || 791 b43_phy_set_baseband_attenuation(dev, bbatt->att);
1109 (q != B43_LOCTL_POISON)) 792 lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
1110 goto error; 793
1111 } 794 lo_measure_restore(dev, &saved_regs);
795 b43_mac_enable(dev);
796
797 if (b43_debug(dev, B43_DBG_LO)) {
798 b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) "
799 "=> I=%d Q=%d\n",
800 bbatt->att, rfatt->att, rfatt->with_padmix,
801 loctl.i, loctl.q);
1112 } 802 }
1113 if (is_initializing && control->used)
1114 goto error;
1115
1116 return;
1117error:
1118 b43err(dev->wl, "LO control pair validation failed "
1119 "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
1120 i, q, control->used,
1121 b43_loctl_is_calibrated(control),
1122 is_initializing);
1123}
1124 803
1125static void validate_all_loctls(struct b43_wldev *dev) 804 cal = kmalloc(sizeof(*cal), GFP_KERNEL);
1126{ 805 if (!cal) {
1127 b43_call_for_each_loctl(dev, do_validate_loctl); 806 b43warn(dev->wl, "LO calib: out of memory\n");
1128} 807 return NULL;
1129
1130static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
1131{
1132 if (dev->phy.lo_control->rebuild ||
1133 control->used) {
1134 b43_loctl_set_calibrated(control, 0);
1135 control->i = B43_LOCTL_POISON;
1136 control->q = B43_LOCTL_POISON;
1137 } 808 }
809 memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
810 memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
811 memcpy(&cal->ctl, &loctl, sizeof(loctl));
812 cal->calib_time = jiffies;
813 INIT_LIST_HEAD(&cal->list);
814
815 return cal;
1138} 816}
1139 817
1140static void reset_all_loctl_calibration_states(struct b43_wldev *dev) 818/* Get a calibrated LO setting for the given attenuation values.
819 * Might return a NULL pointer under OOM! */
820static
821struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
822 const struct b43_bbatt *bbatt,
823 const struct b43_rfatt *rfatt)
1141{ 824{
1142 b43_call_for_each_loctl(dev, do_reset_calib); 825 struct b43_txpower_lo_control *lo = dev->phy.lo_control;
826 struct b43_lo_calib *c;
827
828 c = b43_find_lo_calib(lo, bbatt, rfatt);
829 if (c)
830 return c;
831 /* Not in the list of calibrated LO settings.
832 * Calibrate it now. */
833 c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
834 if (!c)
835 return NULL;
836 list_add(&c->list, &lo->calib_list);
837
838 return c;
1143} 839}
1144 840
1145#else /* B43_DEBUG */ 841void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
1146static inline void validate_all_loctls(struct b43_wldev *dev) { }
1147static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
1148#endif /* B43_DEBUG */
1149
1150void b43_lo_g_measure(struct b43_wldev *dev)
1151{ 842{
1152 struct b43_phy *phy = &dev->phy; 843 struct b43_phy *phy = &dev->phy;
1153 struct lo_g_saved_values uninitialized_var(sav); 844 struct b43_txpower_lo_control *lo = phy->lo_control;
1154 845 int i;
1155 B43_WARN_ON((phy->type != B43_PHYTYPE_B) && 846 int rf_offset, bb_offset;
1156 (phy->type != B43_PHYTYPE_G)); 847 const struct b43_rfatt *rfatt;
1157 848 const struct b43_bbatt *bbatt;
1158 sav.old_channel = phy->channel; 849 u64 power_vector;
1159 lo_measure_setup(dev, &sav); 850 bool table_changed = 0;
1160 reset_all_loctl_calibration_states(dev);
1161 lo_measure(dev);
1162 lo_measure_restore(dev, &sav);
1163
1164 validate_all_loctls(dev);
1165 851
1166 phy->lo_control->lo_measured = 1; 852 BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
1167 phy->lo_control->rebuild = 0; 853 B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
1168}
1169 854
1170#if B43_DEBUG 855 power_vector = lo->power_vector;
1171static void validate_loctl_calibration(struct b43_wldev *dev, 856 if (!update_all && !power_vector)
1172 struct b43_loctl *loctl, 857 return; /* Nothing to do. */
1173 struct b43_rfatt *rfatt, 858
1174 struct b43_bbatt *bbatt) 859 /* Suspend the MAC now to avoid continuous suspend/enable
1175{ 860 * cycles in the loop. */
1176 if (b43_loctl_is_calibrated(loctl)) 861 b43_mac_suspend(dev);
1177 return; 862
1178 if (!dev->phy.lo_control->lo_measured) { 863 for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
1179 /* On init we set the attenuation values before we 864 struct b43_lo_calib *cal;
1180 * calibrated the LO. I guess that's OK. */ 865 int idx;
1181 return; 866 u16 val;
867
868 if (!update_all && !(power_vector & (((u64)1ULL) << i)))
869 continue;
870 /* Update the table entry for this power_vector bit.
871 * The table rows are RFatt entries and columns are BBatt. */
872 bb_offset = i / lo->rfatt_list.len;
873 rf_offset = i % lo->rfatt_list.len;
874 bbatt = &(lo->bbatt_list.list[bb_offset]);
875 rfatt = &(lo->rfatt_list.list[rf_offset]);
876
877 cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
878 if (!cal) {
879 b43warn(dev->wl, "LO: Could not "
880 "calibrate DC table entry\n");
881 continue;
882 }
883 /*FIXME: Is Q really in the low nibble? */
884 val = (u8)(cal->ctl.q);
885 val |= ((u8)(cal->ctl.i)) << 4;
886 kfree(cal);
887
888 /* Get the index into the hardware DC LT. */
889 idx = i / 2;
890 /* Change the table in memory. */
891 if (i % 2) {
892 /* Change the high byte. */
893 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
894 | ((val & 0x00FF) << 8);
895 } else {
896 /* Change the low byte. */
897 lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
898 | (val & 0x00FF);
899 }
900 table_changed = 1;
1182 } 901 }
1183 b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " 902 if (table_changed) {
1184 "control pair: rfatt=%u,%spadmix bbatt=%u\n", 903 /* The table changed in memory. Update the hardware table. */
1185 rfatt->att, 904 for (i = 0; i < B43_DC_LT_SIZE; i++)
1186 (rfatt->with_padmix) ? "" : "no-", 905 b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]);
1187 bbatt->att); 906 }
1188} 907 b43_mac_enable(dev);
1189#else
1190static inline void validate_loctl_calibration(struct b43_wldev *dev,
1191 struct b43_loctl *loctl,
1192 struct b43_rfatt *rfatt,
1193 struct b43_bbatt *bbatt)
1194{
1195} 908}
1196#endif
1197 909
1198static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, 910/* Fixup the RF attenuation value for the case where we are
1199 u8 tx_control) 911 * using the PAD mixer. */
912static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
1200{ 913{
1201 if (tx_control & B43_TXCTL_TXMIX) { 914 if (!rf->with_padmix)
1202 if (rf->att < 5) 915 return;
1203 rf->att = 4; 916 if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
1204 } 917 rf->att = 4;
1205} 918}
1206 919
1207void b43_lo_g_adjust(struct b43_wldev *dev) 920void b43_lo_g_adjust(struct b43_wldev *dev)
1208{ 921{
1209 struct b43_phy *phy = &dev->phy; 922 struct b43_phy *phy = &dev->phy;
923 struct b43_lo_calib *cal;
1210 struct b43_rfatt rf; 924 struct b43_rfatt rf;
1211 struct b43_loctl *loctl;
1212 925
1213 memcpy(&rf, &phy->rfatt, sizeof(rf)); 926 memcpy(&rf, &phy->rfatt, sizeof(rf));
1214 fixup_rfatt_for_txcontrol(&rf, phy->tx_control); 927 b43_lo_fixup_rfatt(&rf);
1215 928
1216 loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); 929 cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
1217 validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); 930 if (!cal)
1218 b43_lo_write(dev, loctl); 931 return;
932 b43_lo_write(dev, &cal->ctl);
1219} 933}
1220 934
1221void b43_lo_g_adjust_to(struct b43_wldev *dev, 935void b43_lo_g_adjust_to(struct b43_wldev *dev,
@@ -1223,39 +937,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
1223{ 937{
1224 struct b43_rfatt rf; 938 struct b43_rfatt rf;
1225 struct b43_bbatt bb; 939 struct b43_bbatt bb;
1226 struct b43_loctl *loctl; 940 struct b43_lo_calib *cal;
1227 941
1228 memset(&rf, 0, sizeof(rf)); 942 memset(&rf, 0, sizeof(rf));
1229 memset(&bb, 0, sizeof(bb)); 943 memset(&bb, 0, sizeof(bb));
1230 rf.att = rfatt; 944 rf.att = rfatt;
1231 bb.att = bbatt; 945 bb.att = bbatt;
1232 fixup_rfatt_for_txcontrol(&rf, tx_control); 946 b43_lo_fixup_rfatt(&rf);
1233 loctl = b43_get_lo_g_ctl(dev, &rf, &bb); 947 cal = b43_get_calib_lo_settings(dev, &bb, &rf);
1234 validate_loctl_calibration(dev, loctl, &rf, &bb); 948 if (!cal)
1235 b43_lo_write(dev, loctl); 949 return;
950 b43_lo_write(dev, &cal->ctl);
1236} 951}
1237 952
1238static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) 953/* Periodic LO maintanance work */
954void b43_lo_g_maintanance_work(struct b43_wldev *dev)
1239{ 955{
1240 control->used = 0; 956 struct b43_phy *phy = &dev->phy;
957 struct b43_txpower_lo_control *lo = phy->lo_control;
958 unsigned long now;
959 unsigned long expire;
960 struct b43_lo_calib *cal, *tmp;
961 bool current_item_expired = 0;
962 bool hwpctl;
963
964 if (!lo)
965 return;
966 now = jiffies;
967 hwpctl = b43_has_hardware_pctl(phy);
968
969 if (hwpctl) {
970 /* Read the power vector and update it, if needed. */
971 expire = now - B43_LO_PWRVEC_EXPIRE;
972 if (time_before(lo->pwr_vec_read_time, expire)) {
973 lo_read_power_vector(dev);
974 b43_gphy_dc_lt_init(dev, 0);
975 }
976 //FIXME Recalc the whole DC table from time to time?
977 }
978
979 if (hwpctl)
980 return;
981 /* Search for expired LO settings. Remove them.
982 * Recalibrate the current setting, if expired. */
983 expire = now - B43_LO_CALIB_EXPIRE;
984 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
985 if (!time_before(cal->calib_time, expire))
986 continue;
987 /* This item expired. */
988 if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
989 b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
990 B43_WARN_ON(current_item_expired);
991 current_item_expired = 1;
992 }
993 if (b43_debug(dev, B43_DBG_LO)) {
994 b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
995 "I=%d, Q=%d expired\n",
996 cal->bbatt.att, cal->rfatt.att,
997 cal->rfatt.with_padmix,
998 cal->ctl.i, cal->ctl.q);
999 }
1000 list_del(&cal->list);
1001 kfree(cal);
1002 }
1003 if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
1004 /* Recalibrate currently used LO setting. */
1005 if (b43_debug(dev, B43_DBG_LO))
1006 b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
1007 cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
1008 if (cal) {
1009 list_add(&cal->list, &lo->calib_list);
1010 b43_lo_write(dev, &cal->ctl);
1011 } else
1012 b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
1013 }
1241} 1014}
1242 1015
1243void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) 1016void b43_lo_g_cleanup(struct b43_wldev *dev)
1244{ 1017{
1245 struct b43_phy *phy = &dev->phy; 1018 struct b43_txpower_lo_control *lo = dev->phy.lo_control;
1246 struct b43_txpower_lo_control *lo = phy->lo_control; 1019 struct b43_lo_calib *cal, *tmp;
1247 1020
1248 b43_call_for_each_loctl(dev, do_mark_unused); 1021 if (!lo)
1249 lo->rebuild = 1; 1022 return;
1023 list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
1024 list_del(&cal->list);
1025 kfree(cal);
1026 }
1250} 1027}
1251 1028
1252void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) 1029/* LO Initialization */
1030void b43_lo_g_init(struct b43_wldev *dev)
1253{ 1031{
1254 struct b43_phy *phy = &dev->phy; 1032 struct b43_phy *phy = &dev->phy;
1255 struct b43_rfatt rf;
1256 1033
1257 memcpy(&rf, &phy->rfatt, sizeof(rf)); 1034 if (b43_has_hardware_pctl(phy)) {
1258 fixup_rfatt_for_txcontrol(&rf, phy->tx_control); 1035 lo_read_power_vector(dev);
1259 1036 b43_gphy_dc_lt_init(dev, 1);
1260 b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; 1037 }
1261} 1038}