Skip to contentSkip to conversation

b43: Rewrite LO calibration algorithm

PATCH In review Michael Buesch 2 participants 2 messages Apr 20, 2008 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 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.

---

John, please apply to 2.6.27

drivers/net/wireless/b43/lo.c +247 -470
Index: wireless-testing/drivers/net/wireless/b43/lo.c
===================================================================
@@ -33,16 +33,28 @@
 #include "main.h"
 
 #include <linux/delay.h>
 #include <linux/sched.h>
 
 
-/* Define to 1 to always calibrate all possible LO control pairs.
- * This is a workaround until we fix the partial LO calibration optimization. */
-#define B43_CALIB_ALL_LOCTLS	1
+static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo,
+					       const struct b43_bbatt *bbatt,
+					       const struct b43_rfatt *rfatt)
+{
+	struct b43_lo_calib *c;
 
+	list_for_each_entry(c, &lo->calib_list, list) {
+		if (!b43_compare_bbatt(&c->bbatt, bbatt))
+			continue;
+		if (!b43_compare_rfatt(&c->rfatt, rfatt))
+			continue;
+		return c;
+	}
+
+	return NULL;
+}
 
 /* Write the LocalOscillator Control (adjust) value-pair. */
 static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
 {
 	struct b43_phy *phy = &dev->phy;
 	u16 value;
@@ -61,189 +73,12 @@ static void b43_lo_write(struct b43_wlde
 	value |= ((u8) (control->i)) << 8;
 
 	reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
 	b43_phy_write(dev, reg, value);
 }
 
-static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
-				  const struct b43_bbatt *bbatt,
-				  struct b43_wldev *dev)
-{
-	int err = 0;
-
-	/* Check the attenuation values against the LO control array sizes. */
-	if (unlikely(rfatt->att >= B43_NR_RF)) {
-		b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
-		err = -EINVAL;
-	}
-	if (unlikely(bbatt->att >= B43_NR_BB)) {
-		b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
-		err = -EINVAL;
-	}
-
-	return err;
-}
-
-#if !B43_CALIB_ALL_LOCTLS
-static
-struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
-					    const struct b43_rfatt *rfatt,
-					    const struct b43_bbatt *bbatt)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
-
-	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
-		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */
-	return &(lo->no_padmix[bbatt->att][rfatt->att]);
-}
-#endif /* !B43_CALIB_ALL_LOCTLS */
-
-struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
-				   const struct b43_rfatt *rfatt,
-				   const struct b43_bbatt *bbatt)
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
-
-	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
-		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */
-	if (rfatt->with_padmix)
-		return &(lo->with_padmix[bbatt->att][rfatt->att]);
-	return &(lo->no_padmix[bbatt->att][rfatt->att]);
-}
-
-/* Call a function for every possible LO control value-pair. */
-static void b43_call_for_each_loctl(struct b43_wldev *dev,
-				    void (*func) (struct b43_wldev *,
-						  struct b43_loctl *))
-{
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *ctl = phy->lo_control;
-	int i, j;
-
-	for (i = 0; i < B43_NR_BB; i++) {
-		for (j = 0; j < B43_NR_RF; j++)
-			func(dev, &(ctl->with_padmix[i][j]));
-	}
-	for (i = 0; i < B43_NR_BB; i++) {
-		for (j = 0; j < B43_NR_RF; j++)
-			func(dev, &(ctl->no_padmix[i][j]));
-	}
-}
-
-static u16 lo_b_r15_loop(struct b43_wldev *dev)
-{
-	int i;
-	u16 ret = 0;
-
-	for (i = 0; i < 10; i++) {
-		b43_phy_write(dev, 0x0015, 0xAFA0);
-		udelay(1);
-		b43_phy_write(dev, 0x0015, 0xEFA0);
-		udelay(10);
-		b43_phy_write(dev, 0x0015, 0xFFA0);
-		udelay(40);
-		ret += b43_phy_read(dev, 0x002C);
-	}
-
-	return ret;
-}
-
-void b43_lo_b_measure(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 regstack[12] = { 0 };
-	u16 mls;
-	u16 fval;
-	int i, j;
-
-	regstack[0] = b43_phy_read(dev, 0x0015);
-	regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
-
-	if (phy->radio_ver == 0x2053) {
-		regstack[2] = b43_phy_read(dev, 0x000A);
-		regstack[3] = b43_phy_read(dev, 0x002A);
-		regstack[4] = b43_phy_read(dev, 0x0035);
-		regstack[5] = b43_phy_read(dev, 0x0003);
-		regstack[6] = b43_phy_read(dev, 0x0001);
-		regstack[7] = b43_phy_read(dev, 0x0030);
-
-		regstack[8] = b43_radio_read16(dev, 0x0043);
-		regstack[9] = b43_radio_read16(dev, 0x007A);
-		regstack[10] = b43_read16(dev, 0x03EC);
-		regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
-
-		b43_phy_write(dev, 0x0030, 0x00FF);
-		b43_write16(dev, 0x03EC, 0x3F3F);
-		b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
-		b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
-	}
-	b43_phy_write(dev, 0x0015, 0xB000);
-	b43_phy_write(dev, 0x002B, 0x0004);
-
-	if (phy->radio_ver == 0x2053) {
-		b43_phy_write(dev, 0x002B, 0x0203);
-		b43_phy_write(dev, 0x002A, 0x08A3);
-	}
-
-	phy->minlowsig[0] = 0xFFFF;
-
-	for (i = 0; i < 4; i++) {
-		b43_radio_write16(dev, 0x0052, regstack[1] | i);
-		lo_b_r15_loop(dev);
-	}
-	for (i = 0; i < 10; i++) {
-		b43_radio_write16(dev, 0x0052, regstack[1] | i);
-		mls = lo_b_r15_loop(dev) / 10;
-		if (mls < phy->minlowsig[0]) {
-			phy->minlowsig[0] = mls;
-			phy->minlowsigpos[0] = i;
-		}
-	}
-	b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
-
-	phy->minlowsig[1] = 0xFFFF;
-
-	for (i = -4; i < 5; i += 2) {
-		for (j = -4; j < 5; j += 2) {
-			if (j < 0)
-				fval = (0x0100 * i) + j + 0x0100;
-			else
-				fval = (0x0100 * i) + j;
-			b43_phy_write(dev, 0x002F, fval);
-			mls = lo_b_r15_loop(dev) / 10;
-			if (mls < phy->minlowsig[1]) {
-				phy->minlowsig[1] = mls;
-				phy->minlowsigpos[1] = fval;
-			}
-		}
-	}
-	phy->minlowsigpos[1] += 0x0101;
-
-	b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
-	if (phy->radio_ver == 0x2053) {
-		b43_phy_write(dev, 0x000A, regstack[2]);
-		b43_phy_write(dev, 0x002A, regstack[3]);
-		b43_phy_write(dev, 0x0035, regstack[4]);
-		b43_phy_write(dev, 0x0003, regstack[5]);
-		b43_phy_write(dev, 0x0001, regstack[6]);
-		b43_phy_write(dev, 0x0030, regstack[7]);
-
-		b43_radio_write16(dev, 0x0043, regstack[8]);
-		b43_radio_write16(dev, 0x007A, regstack[9]);
-
-		b43_radio_write16(dev, 0x0052,
-				  (b43_radio_read16(dev, 0x0052) & 0x000F)
-				  | regstack[11]);
-
-		b43_write16(dev, 0x03EC, regstack[10]);
-	}
-	b43_phy_write(dev, 0x0015, regstack[0]);
-}
-
 static u16 lo_measure_feedthrough(struct b43_wldev *dev,
 				  u16 lna, u16 pga, u16 trsw_rx)
 {
 	struct b43_phy *phy = &dev->phy;
 	u16 rfover;
 	u16 feedthrough;
@@ -435,54 +270,32 @@ static void lo_measure_txctl_values(stru
 	} else {
 		lo->tx_magn = 0;
 		lo->tx_bias = 0;
 		b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
 				  & 0xFFF0);	/* TX bias == 0 */
 	}
+	lo->txctl_measured_time = jiffies;
 }
 
 static void lo_read_power_vector(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	struct b43_txpower_lo_control *lo = phy->lo_control;
-	u16 i;
+	int i;
 	u64 tmp;
 	u64 power_vector = 0;
-	int rf_offset, bb_offset;
-	struct b43_loctl *loctl;
 
 	for (i = 0; i < 8; i += 2) {
 		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
-		/* Clear the top byte. We get holes in the bitmap... */
-		tmp &= 0xFF;
 		power_vector |= (tmp << (i * 8));
 		/* Clear the vector on the device. */
 		b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
 	}
-
 	if (power_vector)
 		lo->power_vector = power_vector;
-	power_vector = lo->power_vector;
-
-	for (i = 0; i < 64; i++) {
-		if (power_vector & ((u64) 1ULL << i)) {
-			/* Now figure out which b43_loctl corresponds
-			 * to this bit.
-			 */
-			rf_offset = i / lo->rfatt_list.len;
-			bb_offset = i % lo->rfatt_list.len;	//FIXME?
-			loctl =
-			    b43_get_lo_g_ctl(dev,
-					     &lo->rfatt_list.list[rf_offset],
-					     &lo->bbatt_list.list[bb_offset]);
-			/* And mark it as "used", as the device told us
-			 * through the bitmap it is using it.
-			 */
-			loctl->used = 1;
-		}
-	}
+	lo->pwr_vec_read_time = jiffies;
 }
 
 /* 802.11/LO/GPHY/MeasuringGains */
 static void lo_measure_gain_values(struct b43_wldev *dev,
 				   s16 max_rx_gain, int use_trsw_rx)
 {
@@ -606,14 +419,12 @@ static void lo_measure_setup(struct b43_
 	}
 	if (phy->type == B43_PHYTYPE_B &&
 	    phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
 		b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
 		b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
 	}
-	if (!lo->rebuild && b43_has_hardware_pctl(phy))
-		lo_read_power_vector(dev);
 	if (phy->rev >= 2) {
 		sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
 		sav->phy_analogoverval =
 		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
 		sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
 		sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
@@ -688,14 +499,18 @@ static void lo_measure_setup(struct b43_
 	if (phy->rev >= 2)
 		b43_dummy_transmission(dev);
 	b43_radio_selectchannel(dev, 6, 0);
 	b43_radio_read16(dev, 0x51);	/* dummy read */
 	if (phy->type == B43_PHYTYPE_G)
 		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
-	if (lo->rebuild)
+
+	/* Re-measure the txctl values, if needed. */
+	if (time_before(lo->txctl_measured_time,
+			jiffies - B43_LO_TXCTL_EXPIRE))
 		lo_measure_txctl_values(dev);
+
 	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
 	} else {
 		if (phy->type == B43_PHYTYPE_B)
 			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		else
@@ -704,13 +519,12 @@ static void lo_measure_setup(struct b43_
 }
 
 static void lo_measure_restore(struct b43_wldev *dev,
 			       struct lo_g_saved_values *sav)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
 	u16 tmp;
 
 	if (phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
 		tmp = (phy->pga_gain << 8);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
@@ -719,20 +533,12 @@ static void lo_measure_restore(struct b4
 		udelay(2);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
 	} else {
 		tmp = (phy->pga_gain | 0xEFA0);
 		b43_phy_write(dev, B43_PHY_PGACTL, tmp);
 	}
-	if (b43_has_hardware_pctl(phy)) {
-		b43_gphy_dc_lt_init(dev);
-	} else {
-		if (lo->rebuild)
-			b43_lo_g_adjust_to(dev, 3, 2, 0);
-		else
-			b43_lo_g_adjust(dev);
-	}
 	if (phy->type == B43_PHYTYPE_G) {
 		if (phy->rev >= 3)
 			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
 		else
 			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		if (phy->rev >= 2)
@@ -790,13 +596,12 @@ struct b43_lo_g_statemachine {
 /* Loop over each possible value in this state. */
 static int lo_probe_possible_loctls(struct b43_wldev *dev,
 				    struct b43_loctl *probe_loctl,
 				    struct b43_lo_g_statemachine *d)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
 	struct b43_loctl test_loctl;
 	struct b43_loctl orig_loctl;
 	struct b43_loctl prev_loctl = {
 		.i = -100,
 		.q = -100,
 	};
@@ -849,13 +654,13 @@ static int lo_probe_possible_loctls(stru
 			if (feedth < d->lowest_feedth) {
 				memcpy(probe_loctl, &test_loctl,
 				       sizeof(struct b43_loctl));
 				found_lower = 1;
 				d->lowest_feedth = feedth;
 				if ((d->nr_measured < 2) &&
-				    (!has_loopback_gain(phy) || lo->rebuild))
+				    !has_loopback_gain(phy))
 					break;
 			}
 		}
 		memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
 		if (i == end)
 			break;
@@ -871,33 +676,32 @@ static int lo_probe_possible_loctls(stru
 
 static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
 					 struct b43_loctl *loctl,
 					 int *max_rx_gain)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
 	struct b43_lo_g_statemachine d;
 	u16 feedth;
 	int found_lower;
 	struct b43_loctl probe_loctl;
 	int max_repeat = 1, repeat_cnt = 0;
 
 	d.nr_measured = 0;
 	d.state_val_multiplier = 1;
-	if (has_loopback_gain(phy) && !lo->rebuild)
+	if (has_loopback_gain(phy))
 		d.state_val_multiplier = 3;
 
 	memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
-	if (has_loopback_gain(phy) && lo->rebuild)
+	if (has_loopback_gain(phy))
 		max_repeat = 4;
 	do {
 		b43_lo_write(dev, &d.min_loctl);
 		feedth = lo_measure_feedthrough(dev, phy->lna_gain,
 						phy->pga_gain,
 						phy->trsw_rx_gain);
-		if (!lo->rebuild && feedth < 0x258) {
+		if (feedth < 0x258) {
 			if (feedth >= 0x12C)
 				*max_rx_gain += 6;
 			else
 				*max_rx_gain += 3;
 			feedth = lo_measure_feedthrough(dev, phy->lna_gain,
 							phy->pga_gain,
@@ -941,321 +745,294 @@ static void lo_probe_loctls_statemachine
 		}
 		lo_measure_gain_values(dev, *max_rx_gain,
 				       has_loopback_gain(phy));
 	} while (++repeat_cnt < max_repeat);
 }
 
-#if B43_CALIB_ALL_LOCTLS
-static const struct b43_rfatt b43_full_rfatt_list_items[] = {
-	{ .att = 0, .with_padmix = 0, },
-	{ .att = 1, .with_padmix = 0, },
-	{ .att = 2, .with_padmix = 0, },
-	{ .att = 3, .with_padmix = 0, },
-	{ .att = 4, .with_padmix = 0, },
-	{ .att = 5, .with_padmix = 0, },
-	{ .att = 6, .with_padmix = 0, },
-	{ .att = 7, .with_padmix = 0, },
-	{ .att = 8, .with_padmix = 0, },
-	{ .att = 9, .with_padmix = 0, },
-	{ .att = 10, .with_padmix = 0, },
-	{ .att = 11, .with_padmix = 0, },
-	{ .att = 12, .with_padmix = 0, },
-	{ .att = 13, .with_padmix = 0, },
-	{ .att = 14, .with_padmix = 0, },
-	{ .att = 15, .with_padmix = 0, },
-	{ .att = 0, .with_padmix = 1, },
-	{ .att = 1, .with_padmix = 1, },
-	{ .att = 2, .with_padmix = 1, },
-	{ .att = 3, .with_padmix = 1, },
-	{ .att = 4, .with_padmix = 1, },
-	{ .att = 5, .with_padmix = 1, },
-	{ .att = 6, .with_padmix = 1, },
-	{ .att = 7, .with_padmix = 1, },
-	{ .att = 8, .with_padmix = 1, },
-	{ .att = 9, .with_padmix = 1, },
-	{ .att = 10, .with_padmix = 1, },
-	{ .att = 11, .with_padmix = 1, },
-	{ .att = 12, .with_padmix = 1, },
-	{ .att = 13, .with_padmix = 1, },
-	{ .att = 14, .with_padmix = 1, },
-	{ .att = 15, .with_padmix = 1, },
-};
-static const struct b43_rfatt_list b43_full_rfatt_list = {
-	.list		= b43_full_rfatt_list_items,
-	.len		= ARRAY_SIZE(b43_full_rfatt_list_items),
-};
-
-static const struct b43_bbatt b43_full_bbatt_list_items[] = {
-	{ .att = 0, },
-	{ .att = 1, },
-	{ .att = 2, },
-	{ .att = 3, },
-	{ .att = 4, },
-	{ .att = 5, },
-	{ .att = 6, },
-	{ .att = 7, },
-	{ .att = 8, },
-	{ .att = 9, },
-	{ .att = 10, },
-	{ .att = 11, },
-};
-static const struct b43_bbatt_list b43_full_bbatt_list = {
-	.list		= b43_full_bbatt_list_items,
-	.len		= ARRAY_SIZE(b43_full_bbatt_list_items),
-};
-#endif /* B43_CALIB_ALL_LOCTLS */
-
-static void lo_measure(struct b43_wldev *dev)
+static
+struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
+					       const struct b43_bbatt *bbatt,
+					       const struct b43_rfatt *rfatt)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
 	struct b43_loctl loctl = {
 		.i = 0,
 		.q = 0,
 	};
-	struct b43_loctl *ploctl;
 	int max_rx_gain;
-	int rfidx, bbidx;
-	const struct b43_bbatt_list *bbatt_list;
-	const struct b43_rfatt_list *rfatt_list;
-
+	struct b43_lo_calib *cal;
+	struct lo_g_saved_values uninitialized_var(saved_regs);
 	/* Values from the "TXCTL Register and Value Table" */
 	u16 txctl_reg;
 	u16 txctl_value;
 	u16 pad_mix_gain;
 
-	bbatt_list = &lo->bbatt_list;
-	rfatt_list = &lo->rfatt_list;
-#if B43_CALIB_ALL_LOCTLS
-	bbatt_list = &b43_full_bbatt_list;
-	rfatt_list = &b43_full_rfatt_list;
-#endif
+	saved_regs.old_channel = phy->channel;
+	b43_mac_suspend(dev);
+	lo_measure_setup(dev, &saved_regs);
 
 	txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
 
-	for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) {
+	b43_radio_write16(dev, 0x43,
+			  (b43_radio_read16(dev, 0x43) & 0xFFF0)
+			  | rfatt->att);
+	b43_radio_write16(dev, txctl_reg,
+			  (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
+			  | (rfatt->with_padmix) ? txctl_value : 0);
 
-		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-					      & 0xFFF0) |
-				  rfatt_list->list[rfidx].att);
-		b43_radio_write16(dev, txctl_reg,
-				  (b43_radio_read16(dev, txctl_reg)
-				   & ~txctl_value)
-				  | (rfatt_list->list[rfidx].with_padmix ?
-				     txctl_value : 0));
-
-		for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
-			if (lo->rebuild) {
-#if B43_CALIB_ALL_LOCTLS
-				ploctl = b43_get_lo_g_ctl(dev,
-							  &rfatt_list->list[rfidx],
-							  &bbatt_list->list[bbidx]);
-#else
-				ploctl = b43_get_lo_g_ctl_nopadmix(dev,
-								   &rfatt_list->
-								   list[rfidx],
-								   &bbatt_list->
-								   list[bbidx]);
-#endif
-			} else {
-				ploctl = b43_get_lo_g_ctl(dev,
-							  &rfatt_list->list[rfidx],
-							  &bbatt_list->list[bbidx]);
-				if (!ploctl->used)
-					continue;
-			}
-			memcpy(&loctl, ploctl, sizeof(loctl));
-			loctl.i = 0;
-			loctl.q = 0;
-
-			max_rx_gain = rfatt_list->list[rfidx].att * 2;
-			max_rx_gain += bbatt_list->list[bbidx].att / 2;
-			if (rfatt_list->list[rfidx].with_padmix)
-				max_rx_gain -= pad_mix_gain;
-			if (has_loopback_gain(phy))
-				max_rx_gain += phy->max_lb_gain;
-			lo_measure_gain_values(dev, max_rx_gain,
-					       has_loopback_gain(phy));
-
-			b43_phy_set_baseband_attenuation(dev,
-							 bbatt_list->list[bbidx].att);
-			lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
-			if (phy->type == B43_PHYTYPE_B) {
-				loctl.i++;
-				loctl.q++;
-			}
-			b43_loctl_set_calibrated(&loctl, 1);
-			memcpy(ploctl, &loctl, sizeof(loctl));
-		}
-	}
-}
+	max_rx_gain = rfatt->att * 2;
+	max_rx_gain += bbatt->att / 2;
+	if (rfatt->with_padmix)
+		max_rx_gain -= pad_mix_gain;
+	if (has_loopback_gain(phy))
+		max_rx_gain += phy->max_lb_gain;
+	lo_measure_gain_values(dev, max_rx_gain,
+			       has_loopback_gain(phy));
 
-#if B43_DEBUG
-static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
-{
-	const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
-	int i = control->i;
-	int q = control->q;
-
-	if (b43_loctl_is_calibrated(control)) {
-		if ((abs(i) > 16) || (abs(q) > 16))
-			goto error;
-	} else {
-		if (control->used)
-			goto error;
-		if (dev->phy.lo_control->rebuild) {
-			control->i = 0;
-			control->q = 0;
-			if ((i != B43_LOCTL_POISON) ||
-			    (q != B43_LOCTL_POISON))
-				goto error;
-		}
-	}
-	if (is_initializing && control->used)
-		goto error;
+	b43_phy_set_baseband_attenuation(dev, bbatt->att);
+	lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
 
-	return;
-error:
-	b43err(dev->wl, "LO control pair validation failed "
-	       "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
-	       i, q, control->used,
-	       b43_loctl_is_calibrated(control),
-	       is_initializing);
-}
+	lo_measure_restore(dev, &saved_regs);
+	b43_mac_enable(dev);
 
-static void validate_all_loctls(struct b43_wldev *dev)
-{
-	b43_call_for_each_loctl(dev, do_validate_loctl);
-}
+	if (b43_debug(dev, B43_DBG_LO)) {
+		b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) "
+		       "=> I=%d Q=%d\n",
+		       bbatt->att, rfatt->att, rfatt->with_padmix,
+		       loctl.i, loctl.q);
+	}
 
-static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
-{
-	if (dev->phy.lo_control->rebuild ||
-	    control->used) {
-		b43_loctl_set_calibrated(control, 0);
-		control->i = B43_LOCTL_POISON;
-		control->q = B43_LOCTL_POISON;
+	cal = kmalloc(sizeof(*cal), GFP_KERNEL);
+	if (!cal) {
+		b43warn(dev->wl, "LO calib: out of memory\n");
+		return NULL;
 	}
-}
+	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
+	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
+	memcpy(&cal->ctl, &loctl, sizeof(loctl));
+	cal->calib_time = jiffies;
+	INIT_LIST_HEAD(&cal->list);
 
-static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
-{
-	b43_call_for_each_loctl(dev, do_reset_calib);
+	return cal;
 }
 
-#else /* B43_DEBUG */
-static inline void validate_all_loctls(struct b43_wldev *dev) { }
-static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
-#endif /* B43_DEBUG */
+/* Get a calibrated LO setting for the given attenuation values.
+ * Might return a NULL pointer under OOM! */
+static
+struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
+						const struct b43_bbatt *bbatt,
+						const struct b43_rfatt *rfatt)
+{
+	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+	struct b43_lo_calib *c;
+
+	c = b43_find_lo_calib(lo, bbatt, rfatt);
+	if (c)
+		return c;
+	/* Not in the list of calibrated LO settings.
+	 * Calibrate it now. */
+	c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
+	if (!c)
+		return NULL;
+	list_add(&c->list, &lo->calib_list);
+
+	return c;
+}
 
-void b43_lo_g_measure(struct b43_wldev *dev)
+void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct lo_g_saved_values uninitialized_var(sav);
-
-	B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
-		    (phy->type != B43_PHYTYPE_G));
-
-	sav.old_channel = phy->channel;
-	lo_measure_setup(dev, &sav);
-	reset_all_loctl_calibration_states(dev);
-	lo_measure(dev);
-	lo_measure_restore(dev, &sav);
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	int i;
+	int rf_offset, bb_offset;
+	const struct b43_rfatt *rfatt;
+	const struct b43_bbatt *bbatt;
+	u64 power_vector;
+	bool table_changed = 0;
 
-	validate_all_loctls(dev);
+	BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
+	B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
 
-	phy->lo_control->lo_measured = 1;
-	phy->lo_control->rebuild = 0;
-}
+	power_vector = lo->power_vector;
+	if (!update_all && !power_vector)
+		return; /* Nothing to do. */
 
-#if B43_DEBUG
-static void validate_loctl_calibration(struct b43_wldev *dev,
-				       struct b43_loctl *loctl,
-				       struct b43_rfatt *rfatt,
-				       struct b43_bbatt *bbatt)
-{
-	if (b43_loctl_is_calibrated(loctl))
-		return;
-	if (!dev->phy.lo_control->lo_measured) {
-		/* On init we set the attenuation values before we
-		 * calibrated the LO. I guess that's OK. */
-		return;
+	/* Suspend the MAC now to avoid continuous suspend/enable
+	 * cycles in the loop. */
+	b43_mac_suspend(dev);
+
+	for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
+		struct b43_lo_calib *cal;
+		int idx;
+		u16 val;
+
+		if (!update_all && !(power_vector & (((u64)1ULL) << i)))
+			continue;
+		/* Update the table entry for this power_vector bit.
+		 * The table rows are RFatt entries and columns are BBatt. */
+		bb_offset = i / lo->rfatt_list.len;
+		rf_offset = i % lo->rfatt_list.len;
+		bbatt = &(lo->bbatt_list.list[bb_offset]);
+		rfatt = &(lo->rfatt_list.list[rf_offset]);
+
+		cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
+		if (!cal) {
+			b43warn(dev->wl, "LO: Could not "
+				"calibrate DC table entry\n");
+			continue;
+		}
+		/*FIXME: Is Q really in the low nibble? */
+		val = (u8)(cal->ctl.q);
+		val |= ((u8)(cal->ctl.i)) << 4;
+		kfree(cal);
+
+		/* Get the index into the hardware DC LT. */
+		idx = i / 2;
+		/* Change the table in memory. */
+		if (i % 2) {
+			/* Change the high byte. */
+			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
+					 | ((val & 0x00FF) << 8);
+		} else {
+			/* Change the low byte. */
+			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
+					 | (val & 0x00FF);
+		}
+		table_changed = 1;
 	}
-	b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
-	       "control pair: rfatt=%u,%spadmix bbatt=%u\n",
-	       rfatt->att,
-	       (rfatt->with_padmix) ? "" : "no-",
-	       bbatt->att);
-}
-#else
-static inline void validate_loctl_calibration(struct b43_wldev *dev,
-					      struct b43_loctl *loctl,
-					      struct b43_rfatt *rfatt,
-					      struct b43_bbatt *bbatt)
-{
+	if (table_changed) {
+		/* The table changed in memory. Update the hardware table. */
+		for (i = 0; i < B43_DC_LT_SIZE; i++)
+			b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]);
+	}
+	b43_mac_enable(dev);
 }
-#endif
 
-static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
-					     u8 tx_control)
+/* Fixup the RF attenuation value for the case where we are
+ * using the PAD mixer. */
+static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
 {
-	if (tx_control & B43_TXCTL_TXMIX) {
-		if (rf->att < 5)
-			rf->att = 4;
-	}
+	if (!rf->with_padmix)
+		return;
+	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
+		rf->att = 4;
 }
 
 void b43_lo_g_adjust(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
+	struct b43_lo_calib *cal;
 	struct b43_rfatt rf;
-	struct b43_loctl *loctl;
 
 	memcpy(&rf, &phy->rfatt, sizeof(rf));
-	fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+	b43_lo_fixup_rfatt(&rf);
 
-	loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
-	validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
-	b43_lo_write(dev, loctl);
+	cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
+	if (!cal)
+		return;
+	b43_lo_write(dev, &cal->ctl);
 }
 
 void b43_lo_g_adjust_to(struct b43_wldev *dev,
 			u16 rfatt, u16 bbatt, u16 tx_control)
 {
 	struct b43_rfatt rf;
 	struct b43_bbatt bb;
-	struct b43_loctl *loctl;
+	struct b43_lo_calib *cal;
 
 	memset(&rf, 0, sizeof(rf));
 	memset(&bb, 0, sizeof(bb));
 	rf.att = rfatt;
 	bb.att = bbatt;
-	fixup_rfatt_for_txcontrol(&rf, tx_control);
-	loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
-	validate_loctl_calibration(dev, loctl, &rf, &bb);
-	b43_lo_write(dev, loctl);
+	b43_lo_fixup_rfatt(&rf);
+	cal = b43_get_calib_lo_settings(dev, &bb, &rf);
+	if (!cal)
+		return;
+	b43_lo_write(dev, &cal->ctl);
 }
 
-static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
+/* Periodic LO maintanance work */
+void b43_lo_g_maintanance_work(struct b43_wldev *dev)
 {
-	control->used = 0;
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	unsigned long now;
+	unsigned long expire;
+	struct b43_lo_calib *cal, *tmp;
+	bool current_item_expired = 0;
+	bool hwpctl;
+
+	if (!lo)
+		return;
+	now = jiffies;
+	hwpctl = b43_has_hardware_pctl(phy);
+
+	if (hwpctl) {
+		/* Read the power vector and update it, if needed. */
+		expire = now - B43_LO_PWRVEC_EXPIRE;
+		if (time_before(lo->pwr_vec_read_time, expire)) {
+			lo_read_power_vector(dev);
+			b43_gphy_dc_lt_init(dev, 0);
+		}
+		//FIXME Recalc the whole DC table from time to time?
+	}
+
+	if (hwpctl)
+		return;
+	/* Search for expired LO settings. Remove them.
+	 * Recalibrate the current setting, if expired. */
+	expire = now - B43_LO_CALIB_EXPIRE;
+	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
+		if (!time_before(cal->calib_time, expire))
+			continue;
+		/* This item expired. */
+		if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
+		    b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
+			B43_WARN_ON(current_item_expired);
+			current_item_expired = 1;
+		}
+		if (b43_debug(dev, B43_DBG_LO)) {
+			b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
+			       "I=%d, Q=%d expired\n",
+			       cal->bbatt.att, cal->rfatt.att,
+			       cal->rfatt.with_padmix,
+			       cal->ctl.i, cal->ctl.q);
+		}
+		list_del(&cal->list);
+		kfree(cal);
+	}
+	if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
+		/* Recalibrate currently used LO setting. */
+		if (b43_debug(dev, B43_DBG_LO))
+			b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
+		cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
+		if (cal) {
+			list_add(&cal->list, &lo->calib_list);
+			b43_lo_write(dev, &cal->ctl);
+		} else
+			b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
+	}
 }
 
-void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+void b43_lo_g_cleanup(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+	struct b43_lo_calib *cal, *tmp;
 
-	b43_call_for_each_loctl(dev, do_mark_unused);
-	lo->rebuild = 1;
+	if (!lo)
+		return;
+	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
+		list_del(&cal->list);
+		kfree(cal);
+	}
 }
 
-void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
+/* LO Initialization */
+void b43_lo_g_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	struct b43_rfatt rf;
-
-	memcpy(&rf, &phy->rfatt, sizeof(rf));
-	fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
 
-	b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1;
+	if (b43_has_hardware_pctl(phy)) {
+		lo_read_power_vector(dev);
+		b43_gphy_dc_lt_init(dev, 1);
+	}
 }
drivers/net/wireless/b43/lo.h +44 -71

150 lines not on this page · raw message

drivers/net/wireless/b43/main.c +5 -21
Index: wireless-testing/drivers/net/wireless/b43/main.c
===================================================================
@@ -2298,13 +2298,13 @@ static void b43_gpio_cleanup(struct b43_
 	if (!gpiodev)
 		return;
 	ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
-static void b43_mac_enable(struct b43_wldev *dev)
+void b43_mac_enable(struct b43_wldev *dev)
 {
 	dev->mac_suspended--;
 	B43_WARN_ON(dev->mac_suspended < 0);
 	if (dev->mac_suspended == 0) {
 		b43_write32(dev, B43_MMIO_MACCTL,
 			    b43_read32(dev, B43_MMIO_MACCTL)
@@ -2321,13 +2321,13 @@ static void b43_mac_enable(struct b43_wl
 		b43_interrupt_enable(dev, dev->irq_savedstate);
 		spin_unlock_irq(&dev->wl->irq_lock);
 	}
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
-static void b43_mac_suspend(struct b43_wldev *dev)
+void b43_mac_suspend(struct b43_wldev *dev)
 {
 	int i;
 	u32 tmp;
 
 	might_sleep();
 	B43_WARN_ON(dev->mac_suspended < 0);
@@ -2493,12 +2493,13 @@ static void b43_mgmtframe_txantenna(stru
 
 /* This is the opposite of b43_chip_init() */
 static void b43_chip_exit(struct b43_wldev *dev)
 {
 	b43_radio_turn_off(dev, 1);
 	b43_gpio_cleanup(dev);
+	b43_lo_g_cleanup(dev);
 	/* firmware is released later */
 }
 
 /* Initialize the chip
  * http://bcm-specs.sipsolutions.net/ChipInit
  */
@@ -2599,34 +2600,18 @@ err_radio_off:
 	b43_radio_turn_off(dev, 1);
 err_gpio_clean:
 	b43_gpio_cleanup(dev);
 	return err;
 }
 
-static void b43_periodic_every120sec(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-
-	if (phy->type != B43_PHYTYPE_G || phy->rev < 2)
-		return;
-
-	b43_mac_suspend(dev);
-	b43_lo_g_measure(dev);
-	b43_mac_enable(dev);
-	if (b43_has_hardware_pctl(phy))
-		b43_lo_g_ctl_mark_all_unused(dev);
-}
-
 static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 
 	if (phy->type != B43_PHYTYPE_G)
 		return;
-	if (!b43_has_hardware_pctl(phy))
-		b43_lo_g_ctl_mark_all_unused(dev);
 	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 		b43_mac_suspend(dev);
 		b43_calc_nrssi_slope(dev);
 		if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
 			u8 old_chan = phy->channel;
 
@@ -2672,25 +2657,24 @@ static void b43_periodic_every15sec(stru
 		} else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
 			   phy->rev == 1) {
 			//TODO: implement rev1 workaround
 		}
 	}
 	b43_phy_xmitpower(dev);	//FIXME: unless scanning?
+	b43_lo_g_maintanance_work(dev);
 	//TODO for APHY (temperature?)
 
 	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
 	wmb();
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
 {
 	unsigned int state;
 
 	state = dev->periodic_state;
-	if (state % 8 == 0)
-		b43_periodic_every120sec(dev);
 	if (state % 4 == 0)
 		b43_periodic_every60sec(dev);
 	if (state % 2 == 0)
 		b43_periodic_every30sec(dev);
 	b43_periodic_every15sec(dev);
 }
@@ -3651,14 +3635,14 @@ static void setup_struct_phy_for_init(st
 
 	phy->radio_off_context.valid = 0;
 
 	lo = phy->lo_control;
 	if (lo) {
 		memset(lo, 0, sizeof(*(phy->lo_control)));
-		lo->rebuild = 1;
 		lo->tx_bias = 0xFF;
+		INIT_LIST_HEAD(&lo->calib_list);
 	}
 	phy->max_lb_gain = 0;
 	phy->trsw_rx_gain = 0;
 	phy->txpwr_offset = 0;
 
 	/* NRSSI */
drivers/net/wireless/b43/phy.c +33 -90

269 lines not on this page · raw message

drivers/net/wireless/b43/phy.h +15 -1
Index: wireless-testing/drivers/net/wireless/b43/phy.h
===================================================================
@@ -222,13 +222,12 @@ int b43_phy_init_tssi2dbm_table(struct b
 void b43_phy_early_init(struct b43_wldev *dev);
 int b43_phy_init(struct b43_wldev *dev);
 
 void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
 
 void b43_phy_xmitpower(struct b43_wldev *dev);
-void b43_gphy_dc_lt_init(struct b43_wldev *dev);
 
 /* Returns the boolean whether the board has HardwarePowerControl */
 bool b43_has_hardware_pctl(struct b43_phy *phy);
 /* Returns the boolean whether "TX Magnification" is enabled. */
 #define has_tx_magnification(phy) \
 	(((phy)->rev >= 2) &&			\
@@ -249,12 +248,20 @@ struct b43_rfatt_list {
 	u8 len;
 	/* Minimum/Maximum attenuation values */
 	u8 min_val;
 	u8 max_val;
 };
 
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
+				     const struct b43_rfatt *b)
+{
+	return ((a->att == b->att) &&
+		(a->with_padmix == b->with_padmix));
+}
+
 /* Baseband Attenuation */
 struct b43_bbatt {
 	u8 att;			/* Attenuation value */
 };
 struct b43_bbatt_list {
 	/* Attenuation values list */
@@ -262,12 +269,19 @@ struct b43_bbatt_list {
 	u8 len;
 	/* Minimum/Maximum attenuation values */
 	u8 min_val;
 	u8 max_val;
 };
 
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
+				     const struct b43_bbatt *b)
+{
+	return (a->att == b->att);
+}
+
 /* tx_control bits. */
 #define B43_TXCTL_PA3DB		0x40	/* PA Gain 3dB */
 #define B43_TXCTL_PA2DB		0x20	/* PA Gain 2dB */
 #define B43_TXCTL_TXMIX		0x10	/* TX Mixer Gain */
 
 /* Write BasebandAttenuation value to the device. */
drivers/net/wireless/b43/debugfs.c +47 -32

145 lines not on this page · raw message

drivers/net/wireless/b43/debugfs.h +1 -0
Index: wireless-testing/drivers/net/wireless/b43/debugfs.h
===================================================================
@@ -7,12 +7,13 @@ struct b43_txstatus;
 enum b43_dyndbg {		/* Dynamic debugging features */
 	B43_DBG_XMITPOWER,
 	B43_DBG_DMAOVERFLOW,
 	B43_DBG_DMAVERBOSE,
 	B43_DBG_PWORK_FAST,
 	B43_DBG_PWORK_STOP,
+	B43_DBG_LO,
 	__B43_NR_DYNDBG,
 };
 
 #ifdef CONFIG_B43_DEBUG
 
 struct dentry;
drivers/net/wireless/b43/main.h +3 -0
Index: wireless-testing/drivers/net/wireless/b43/main.h
===================================================================
@@ -111,7 +111,10 @@ void b43_controller_restart(struct b43_w
 #define B43_PS_ENABLED	(1 << 0)	/* Force enable hardware power saving */
 #define B43_PS_DISABLED	(1 << 1)	/* Force disable hardware power saving */
 #define B43_PS_AWAKE	(1 << 2)	/* Force device awake */
 #define B43_PS_ASLEEP	(1 << 3)	/* Force device asleep */
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
 
+void b43_mac_suspend(struct b43_wldev *dev);
+void b43_mac_enable(struct b43_wldev *dev);
+
 #endif /* B43_MAIN_H_ */
Acked-by on v1 1/1
#1 lore raw
Quoted 13 lines · Michael Buesch

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.

Quoted 6 lines

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.

Quoted 1 line

---