Skip to contentSkip to conversation

b43: LP-PHY: Begin implementing calibration & software RFKILL support

PATCH In review Gábor Stefanik 4 participants 9 messages Aug 30, 2009 – Sep 1, 2009 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 b43: LP-PHY: Begin implementing calibration & software RFKILL support

This implements the following calibration functions:
-Set TX IQCC
-Set TX Power by Index
-PR41573 workaround
-Calc RX IQ Comp
-PHY Cordic
-Run Samples
-Start/Stop TX Tone
-part of PAPD Cal TX Power
-RX I/Q Calibration
-The basic structure of the periodic calibration wrapper

Software RFKILL (required by calibration) is also implemented in this round.

---
V2: Fix a mistake I made in the PHY Cordic routine.

drivers/net/wireless/b43/main.c   |    2 +-
drivers/net/wireless/b43/main.h   |    2 +
drivers/net/wireless/b43/phy_lp.c |  686 ++++++++++++++++++++++++++++++++-----
drivers/net/wireless/b43/phy_lp.h |   11 +-
4 files changed, 613 insertions(+), 88 deletions(-)
drivers/net/wireless/b43/main.c +0 -0
index f2c5b2d..59bee02 100644
@@ -3345,7 +3345,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
	mutex_unlock(&wl->mutex);
}

-static void b43_put_phy_into_reset(struct b43_wldev *dev) +void b43_put_phy_into_reset(struct b43_wldev *dev)

{
	struct ssb_device *sdev = dev->dev;
	u32 tmslow;
drivers/net/wireless/b43/main.h +0 -0
index 0406e06..fdbea9a 100644
@@ -129,6 +129,8 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
 

void b43_controller_restart(struct b43_wldev *dev, const char *reason);

+void b43_put_phy_into_reset(struct b43_wldev *dev); +
#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 */

drivers/net/wireless/b43/phy_lp.c +0 -0
index 5fff30a..c13385b 100644
@@ -67,6 +67,7 @@ static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
	struct b43_phy_lp *lpphy = phy->lp;

	memset(lpphy, 0, sizeof(*lpphy));

+ lpphy->antenna = B43_ANTENNA_DEFAULT;

	//TODO
}
@@ -751,11 +752,17 @@ static void lpphy_clear_deaf(struct b43_wldev *dev, bool user)
	}
}

+static void lpphy_set_trsw_over(struct b43_wldev *dev, bool tx, bool rx) +{
+ u16 trsw = (tx << 1) | rx;
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, trsw);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+}
+
static void lpphy_disable_crs(struct b43_wldev *dev, bool user)

{
	lpphy_set_deaf(dev, user);
-	b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
-	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+	lpphy_set_trsw_over(dev, false, true);
	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFB);
	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x4);
	b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFF7);

@@ -790,6 +797,60 @@ static void lpphy_restore_crs(struct b43_wldev *dev, bool user)

struct lpphy_tx_gains { u16 gm, pga, pad, dac; };

+static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) +{
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
+ if (dev->phy.rev >= 2) {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+ b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
+ }
+ } else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
+ }
+}
+
+static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) +{
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+ if (dev->phy.rev >= 2) {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+ b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
+ }
+ } else {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
+ }
+}
+
+static void lpphy_disable_tx_gain_override(struct b43_wldev *dev) +{
+ if (dev->phy.rev < 2)
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
+ else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF);
+ }
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF);
+}
+
+static void lpphy_enable_tx_gain_override(struct b43_wldev *dev) +{
+ if (dev->phy.rev < 2)
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
+ else {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x80);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x4000);
+ }
+ b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x40);
+}
+
static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)

{
	struct lpphy_tx_gains gains;
@@ -819,6 +880,17 @@ static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
	b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
}

+static u16 lpphy_get_pa_gain(struct b43_wldev *dev)
+{
+ return b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x7F;
+}
+
+static void lpphy_set_pa_gain(struct b43_wldev *dev, u16 gain) +{
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), 0xE03F, gain << 6);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xFD), 0x80FF, gain << 8);
+}
+
static void lpphy_set_tx_gains(struct b43_wldev *dev,
struct lpphy_tx_gains gains)
{
@@ -829,8 +901,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,

		b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
				0xF800, rf_gain);
	} else {
-		pa_gain = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0x1FC0;
-		pa_gain <<= 2;
+		pa_gain = lpphy_get_pa_gain(dev);
		b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
			      (gains.pga << 8) | gains.gm);
		b43_phy_maskset(dev, B43_PHY_OFDM(0xFB),
@@ -841,13 +912,7 @@ static void lpphy_set_tx_gains(struct b43_wldev *dev,
				0x8000, gains.pad | pa_gain);
	}
	lpphy_set_dac_gain(dev, gains.dac);

- if (dev->phy.rev < 2) {
- b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF, 1 << 8);
- } else {
- b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFF7F, 1 << 7);
- b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2, 0xBFFF, 1 << 14);
- }
- b43_phy_maskset(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFBF, 1 << 6);
+ lpphy_enable_tx_gain_override(dev);
}

static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
@@ -887,38 +952,6 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)

	}
}

-static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) -{
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFEF);
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFBF);
- if (dev->phy.rev >= 2) {
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFEFF);
- if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
- b43_phy_mask(dev, B43_PHY_OFDM(0xE5), 0xFFF7);
- }
- } else {
- b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
- }
-}
-
-static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) -{
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1);
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
- if (dev->phy.rev >= 2) {
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x100);
- if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
- b43_phy_set(dev, B43_PHY_OFDM(0xE5), 0x8);
- }
- } else {
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x200);
- }
-}
-
static void lpphy_set_rx_gain(struct b43_wldev *dev, u32 gain)

{
	if (dev->phy.rev < 2)

@@ -1003,8 +1036,7 @@ static int lpphy_loopback(struct b43_wldev *dev)

	memset(&iq_est, 0, sizeof(iq_est));

- b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x3);
- b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);

+	lpphy_set_trsw_over(dev, true, true);
	b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 1);
	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
	b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
@@ -1126,7 +1158,7 @@ static void lpphy_set_tx_power_control(struct b43_wldev *dev,
			b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM,
					0x8FFF, ((u16)lpphy->tssi_npt << 16));
			//TODO Set "TSSI Transmit Count" variable to total transmitted frame count
-			//TODO Disable TX gain override
+			lpphy_disable_tx_gain_override(dev);
			lpphy->tx_pwr_idx_over = -1;
		}
	}
@@ -1312,15 +1344,73 @@ static void lpphy_calibrate_rc(struct b43_wldev *dev)
	}
}

+static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{
+ if (dev->phy.rev >= 2)
+ return; // rev2+ doesn't support antenna diversity
+
+ if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
+ return;
+
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ANTDIVHELP);
+
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
+
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ANTDIVHELP);
+
+ dev->phy.lp->antenna = antenna;
+}
+
+static void lpphy_set_tx_iqcc(struct b43_wldev *dev, u16 a, u16 b) +{
+ u16 tmp[2];
+
+ tmp[0] = a;
+ tmp[1] = b;
+ b43_lptab_write_bulk(dev, B43_LPTAB16(0, 80), 2, tmp);
+}
+
static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index)

{
	struct b43_phy_lp *lpphy = dev->phy.lp;

+ struct lpphy_tx_gains gains;
+ u32 iq_comp, tx_gain, coeff, rf_power;

	lpphy->tx_pwr_idx_over = index;
+	lpphy_read_tx_pctl_mode_from_hardware(dev);
	if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF)
		lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW);

-
- //TODO
+ if (dev->phy.rev >= 2) {
+ iq_comp = b43_lptab_read(dev, B43_LPTAB32(7, index + 320));
+ tx_gain = b43_lptab_read(dev, B43_LPTAB32(7, index + 192));
+ gains.pad = (tx_gain >> 16) & 0xFF;
+ gains.gm = tx_gain & 0xFF;
+ gains.pga = (tx_gain >> 8) & 0xFF;
+ gains.dac = (iq_comp >> 28) & 0xFF;
+ lpphy_set_tx_gains(dev, gains);
+ } else {
+ iq_comp = b43_lptab_read(dev, B43_LPTAB32(10, index + 320));
+ tx_gain = b43_lptab_read(dev, B43_LPTAB32(10, index + 192));
+ b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ 0xF800, (tx_gain >> 4) & 0x7FFF);
+ lpphy_set_dac_gain(dev, tx_gain & 0x7);
+ lpphy_set_pa_gain(dev, (tx_gain >> 24) & 0x7F);
+ }
+ lpphy_set_bb_mult(dev, (iq_comp >> 20) & 0xFF);
+ lpphy_set_tx_iqcc(dev, (iq_comp >> 10) & 0x3FF, iq_comp & 0x3FF);
+ if (dev->phy.rev >= 2) {
+ coeff = b43_lptab_read(dev, B43_LPTAB32(7, index + 448));
+ } else {
+ coeff = b43_lptab_read(dev, B43_LPTAB32(10, index + 448));
+ }
+ b43_lptab_write(dev, B43_LPTAB16(0, 85), coeff & 0xFFFF);
+ if (dev->phy.rev >= 2) {
+ rf_power = b43_lptab_read(dev, B43_LPTAB32(7, index + 576));
+ b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00,
+ rf_power & 0xFFFF);//SPEC FIXME mask & set != 0
+ }
+ lpphy_enable_tx_gain_override(dev);
}

static void lpphy_btcoex_override(struct b43_wldev *dev)
@@ -1329,6 +1419,47 @@ static void lpphy_btcoex_override(struct b43_wldev *dev)

	b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF);
}

+static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
+ bool blocked)
+{
+ //TODO check MAC control register
+ if (blocked) {
+ if (dev->phy.rev >= 2) {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x83FF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0x80FF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xDFFF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0808);
+ } else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xE0FF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x1F00);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFCFF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x0018);
+ }
+ } else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xE0FF);
+ if (dev->phy.rev >= 2)
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xF7F7);
+ else
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFE7);
+ }
+}
+
+/* This was previously called lpphy_japan_filter */
+static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel) +{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
+
+ if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
+ b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
+ if ((dev->phy.rev == 1) && (lpphy->rc_cap))
+ lpphy_set_rc_cap(dev);
+ } else {
+ b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
+ }
+}
+
static void lpphy_pr41573_workaround(struct b43_wldev *dev)

{
	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
				    saved_tab_size, saved_tab);
	}

+ b43_put_phy_into_reset(dev);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFF8);
+ lpphy_table_init(dev); //FIXME is table init needed?
+ lpphy_baseband_init(dev);
+ b43_lpphy_op_software_rfkill(dev, false);
+ lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+ if (dev->phy.rev < 2) {
+ b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
+ saved_tab_size, saved_tab);
+ } else {
+ b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
+ saved_tab_size, saved_tab);
+ }
+ b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
+ lpphy->tssi_npt = tssi_npt;
+ lpphy->tssi_idx = tssi_idx;
+ lpphy_set_analog_filter(dev, lpphy->channel);
+ if (tx_pwr_idx_over != -1)
+ lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
+ if (lpphy->rc_cap)
+ lpphy_set_rc_cap(dev);
+ b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
+ lpphy_set_tx_power_control(dev, txpctl_mode);
+ kfree(saved_tab);
+}
+
+struct lpphy_rx_iq_comp { u8 chan; s8 c1, c0; };
+
+static const struct lpphy_rx_iq_comp lpphy_5354_iq_table[] = {
+ { .chan = 1, .c1 = -66, .c0 = 15, },
+ { .chan = 2, .c1 = -66, .c0 = 15, },
+ { .chan = 3, .c1 = -66, .c0 = 15, },
+ { .chan = 4, .c1 = -66, .c0 = 15, },
+ { .chan = 5, .c1 = -66, .c0 = 15, },
+ { .chan = 6, .c1 = -66, .c0 = 15, },
+ { .chan = 7, .c1 = -66, .c0 = 14, },
+ { .chan = 8, .c1 = -66, .c0 = 14, },
+ { .chan = 9, .c1 = -66, .c0 = 14, },
+ { .chan = 10, .c1 = -66, .c0 = 14, },
+ { .chan = 11, .c1 = -66, .c0 = 14, },
+ { .chan = 12, .c1 = -66, .c0 = 13, },
+ { .chan = 13, .c1 = -66, .c0 = 13, },
+ { .chan = 14, .c1 = -66, .c0 = 13, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev0_1_iq_table[] = {
+ { .chan = 1, .c1 = -64, .c0 = 13, },
+ { .chan = 2, .c1 = -64, .c0 = 13, },
+ { .chan = 3, .c1 = -64, .c0 = 13, },
+ { .chan = 4, .c1 = -64, .c0 = 13, },
+ { .chan = 5, .c1 = -64, .c0 = 12, },
+ { .chan = 6, .c1 = -64, .c0 = 12, },
+ { .chan = 7, .c1 = -64, .c0 = 12, },
+ { .chan = 8, .c1 = -64, .c0 = 12, },
+ { .chan = 9, .c1 = -64, .c0 = 12, },
+ { .chan = 10, .c1 = -64, .c0 = 11, },
+ { .chan = 11, .c1 = -64, .c0 = 11, },
+ { .chan = 12, .c1 = -64, .c0 = 11, },
+ { .chan = 13, .c1 = -64, .c0 = 11, },
+ { .chan = 14, .c1 = -64, .c0 = 10, },
+ { .chan = 34, .c1 = -62, .c0 = 24, },
+ { .chan = 38, .c1 = -62, .c0 = 24, },
+ { .chan = 42, .c1 = -62, .c0 = 24, },
+ { .chan = 46, .c1 = -62, .c0 = 23, },
+ { .chan = 36, .c1 = -62, .c0 = 24, },
+ { .chan = 40, .c1 = -62, .c0 = 24, },
+ { .chan = 44, .c1 = -62, .c0 = 23, },
+ { .chan = 48, .c1 = -62, .c0 = 23, },
+ { .chan = 52, .c1 = -62, .c0 = 23, },
+ { .chan = 56, .c1 = -62, .c0 = 22, },
+ { .chan = 60, .c1 = -62, .c0 = 22, },
+ { .chan = 64, .c1 = -62, .c0 = 22, },
+ { .chan = 100, .c1 = -62, .c0 = 16, },
+ { .chan = 104, .c1 = -62, .c0 = 16, },
+ { .chan = 108, .c1 = -62, .c0 = 15, },
+ { .chan = 112, .c1 = -62, .c0 = 14, },
+ { .chan = 116, .c1 = -62, .c0 = 14, },
+ { .chan = 120, .c1 = -62, .c0 = 13, },
+ { .chan = 124, .c1 = -62, .c0 = 12, },
+ { .chan = 128, .c1 = -62, .c0 = 12, },
+ { .chan = 132, .c1 = -62, .c0 = 12, },
+ { .chan = 136, .c1 = -62, .c0 = 11, },
+ { .chan = 140, .c1 = -62, .c0 = 10, },
+ { .chan = 149, .c1 = -61, .c0 = 9, },
+ { .chan = 153, .c1 = -61, .c0 = 9, },
+ { .chan = 157, .c1 = -61, .c0 = 9, },
+ { .chan = 161, .c1 = -61, .c0 = 8, },
+ { .chan = 165, .c1 = -61, .c0 = 8, },
+ { .chan = 184, .c1 = -62, .c0 = 25, },
+ { .chan = 188, .c1 = -62, .c0 = 25, },
+ { .chan = 192, .c1 = -62, .c0 = 25, },
+ { .chan = 196, .c1 = -62, .c0 = 25, },
+ { .chan = 200, .c1 = -62, .c0 = 25, },
+ { .chan = 204, .c1 = -62, .c0 = 25, },
+ { .chan = 208, .c1 = -62, .c0 = 25, },
+ { .chan = 212, .c1 = -62, .c0 = 25, },
+ { .chan = 216, .c1 = -62, .c0 = 26, },
+};
+
+static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
+ .chan = 0,
+ .c1 = -64,
+ .c0 = 0,
+};
+
+static u8 lpphy_nbits(s32 val)
+{
+ u32 tmp = abs(val);
+ u8 nbits = 0;
+
+ while (tmp != 0) {
+ nbits++;
+ tmp >>= 1;
+ }
+
+ return nbits;
+}
+
+static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) +{
+ struct lpphy_iq_est iq_est;
+ u16 c0, c1;
+ int prod, ipwr, qpwr, prod_msb, q_msb, tmp1, tmp2, tmp3, tmp4, ret;
+
+ c1 = b43_phy_read(dev, B43_LPPHY_RX_COMP_COEFF_S);
+ c0 = c1 >> 8;
+ c1 |= 0xFF;
+
+ b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, 0x00C0);
+ b43_phy_mask(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF);
+
+ ret = lpphy_rx_iq_est(dev, samples, 32, &iq_est);
+ if (!ret)
+ goto out;
+
+ prod = iq_est.iq_prod;
+ ipwr = iq_est.i_pwr;
+ qpwr = iq_est.q_pwr;
+
+ if (ipwr + qpwr < 2) {
+ ret = 0;
+ goto out;
+ }
+
+ prod_msb = lpphy_nbits(prod);
+ q_msb = lpphy_nbits(qpwr);
+ tmp1 = prod_msb - 20;
+
+ if (tmp1 >= 0) {
+ tmp3 = ((prod << (30 - prod_msb)) + (ipwr >> (1 + tmp1))) /
+ (ipwr >> tmp1);
+ } else {
+ tmp3 = ((prod << (30 - prod_msb)) + (ipwr << (-1 - tmp1))) /
+ (ipwr << -tmp1);
+ }
+
+ tmp2 = q_msb - 11;
+
+ if (tmp2 >= 0)
+ tmp4 = (qpwr << (31 - q_msb)) / (ipwr >> tmp2);
+ else
+ tmp4 = (qpwr << (31 - q_msb)) / (ipwr << -tmp2);
+
+ tmp4 -= tmp3 * tmp3;
+ tmp4 = -int_sqrt(tmp4);
+
+ c0 = tmp3 >> 3;
+ c1 = tmp4 >> 4;
+
+out:
+ b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, c1);
+ b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0x00FF, c0 << 8);
+ return ret;
+}
+
+/* Complex number using 2 32-bit signed integers */
+typedef struct {s32 i, q;} lpphy_c32;
+
+static lpphy_c32 lpphy_cordic(int theta)
+{
+ u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
+ 58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
+ 229, 115, 57, 29, };
+ int i, tmp, signx = 1, angle = 0;
+ lpphy_c32 ret = { .i = 39797, .q = 0, };
+
+ theta = clamp_t(int, theta, -180, 180);
+
+ if (theta > 90) {
+ theta -= 180;
+ signx = -1;
+ } else if (theta < -90) {
+ theta += 180;
+ signx = -1;
+ }
+
+ for (i = 0; i <= 17; i++) {
+ if (theta > angle) {
+ tmp = ret.i - (ret.q >> i);
+ ret.q += ret.i >> i;
+ ret.i = tmp;
+ angle += arctg[i];
+ } else {
+ tmp = ret.i + (ret.q >> i);
+ ret.q -= ret.i >> i;
+ ret.i = tmp;
+ angle -= arctg[i];
+ }
+ }
+
+ ret.i *= signx;
+ ret.q *= signx;
+
+ return ret;
+}
+
+static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
+ u16 wait)
+{
+ b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL,
+ 0xFFC0, samples - 1);
+ if (loops != 0xFFFF)
+ loops--;
+ b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000, loops);
+ b43_phy_maskset(dev, B43_LPPHY_SMPL_PLAY_BUFFER_CTL, 0x3F, wait << 6);
+ b43_phy_set(dev, B43_LPPHY_A_PHY_CTL_ADDR, 0x1);
+}
+
+//SPEC FIXME what does a negative freq mean?
+static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max) +{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ u16 buf[64];
+ int i, samples, angle = 0, rotation = (9 * freq) / 500;
+ lpphy_c32 sample;
+
+ lpphy->tx_tone_freq = freq;
+
+ if (freq) {
+ /* Find i for which abs(freq) integrally divides 20000 * i */
+ for (i = 1; samples * abs(freq) != 20000 * i; i++) {
+ samples = (20000 * i) / abs(freq);
+ if(B43_WARN_ON(samples > 63))
+ return;
+ }
+ } else {
+ samples = 2;
+ }
+
+ for (i = 0; i < samples; i++) {
+ sample = lpphy_cordic(angle);
+ angle += rotation;
+ buf[i] = ((sample.i * max) & 0xFF) << 8;
+ buf[i] |= (sample.q * max) & 0xFF;
+ }
+
+ b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
+
+ lpphy_run_samples(dev, samples, 0xFFFF, 0);
+}
+
+static void lpphy_stop_tx_tone(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ int i;
+
+ lpphy->tx_tone_freq = 0;
+
+ b43_phy_mask(dev, B43_LPPHY_SMPL_PLAY_COUNT, 0xF000);
+ for (i = 0; i < 31; i++) {
+ if (!(b43_phy_read(dev, B43_LPPHY_A_PHY_CTL_ADDR) & 0x1))
+ break;
+ udelay(100);
+ }
+}
+
+
+static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
+ int mode, bool useindex, u8 index)

+{
	//TODO

+}

- kfree(saved_tab);
+static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct lpphy_tx_gains gains, oldgains;
+ int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
+
+ lpphy_read_tx_pctl_mode_from_hardware(dev);
+ old_txpctl = lpphy->txpctl_mode;
+ old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+ if (old_afe_ovr)
+ oldgains = lpphy_get_tx_gains(dev);
+ old_rf = b43_phy_read(dev, B43_LPPHY_RF_PWR_OVERRIDE) & 0xFF;
+ old_bbmult = lpphy_get_bb_mult(dev);
+
+ lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+
+ if (bus->chip_id == 0x4325 && bus->chip_rev == 0)
+ lpphy_papd_cal(dev, gains, 0, 1, 30);
+ else
+ lpphy_papd_cal(dev, gains, 0, 1, 65);
+
+ if (old_afe_ovr)
+ lpphy_set_tx_gains(dev, oldgains);
+ lpphy_set_bb_mult(dev, old_bbmult);
+ lpphy_set_tx_power_control(dev, old_txpctl);
+ b43_phy_maskset(dev, B43_LPPHY_RF_PWR_OVERRIDE, 0xFF00, old_rf);
+}
+
+static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
+ bool rx, bool pa, struct lpphy_tx_gains *gains)
+{
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ struct ssb_bus *bus = dev->dev->bus;
+ const struct lpphy_rx_iq_comp *iqcomp = NULL;
+ struct lpphy_tx_gains nogains, oldgains;
+ u16 tmp;
+ int i, ret;
+
+ memset(&nogains, 0, sizeof(nogains));
+ memset(&oldgains, 0, sizeof(oldgains));
+
+ if (bus->chip_id == 0x5354) {
+ for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
+ if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
+ iqcomp = &lpphy_5354_iq_table[i];
+ }
+ }
+ } else if (dev->phy.rev >= 2) {
+ iqcomp = &lpphy_rev2plus_iq_comp;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(lpphy_rev0_1_iq_table); i++) {
+ if (lpphy_rev0_1_iq_table[i].chan == lpphy->channel) {
+ iqcomp = &lpphy_rev0_1_iq_table[i];
+ }
+ }
+ }
+
+ if (B43_WARN_ON(!iqcomp))
+ return 0;
+
+ b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S, 0xFF00, iqcomp->c1);
+ b43_phy_maskset(dev, B43_LPPHY_RX_COMP_COEFF_S,
+ 0x00FF, iqcomp->c0 << 8);
+
+ if (noise) {
+ tx = true;
+ rx = false;
+ pa = false;
+ }
+
+ lpphy_set_trsw_over(dev, tx, rx);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+ 0xFFF7, pa << 3);
+ } else {
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0,
+ 0xFFDF, pa << 5);
+ }
+
+ tmp = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) & 0x40;
+
+ if (noise)
+ lpphy_set_rx_gain(dev, 0x2D5D);
+ else {
+ if (tmp)
+ oldgains = lpphy_get_tx_gains(dev);
+ if (!gains)
+ gains = &nogains;
+ lpphy_set_tx_gains(dev, *gains);
+ }
+
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xFFFE);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x800);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x800);
+ lpphy_set_deaf(dev, false);
+ if (noise)
+ ret = lpphy_calc_rx_iq_comp(dev, 0xFFF0);
+ else {
+ lpphy_start_tx_tone(dev, 4000, 100);
+ ret = lpphy_calc_rx_iq_comp(dev, 0x4000);
+ lpphy_stop_tx_tone(dev);
+ }
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFC);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFF7);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFDF);
+ if (!noise) {
+ if (tmp)
+ lpphy_set_tx_gains(dev, oldgains);
+ else
+ lpphy_disable_tx_gain_override(dev);
+ }
+ lpphy_disable_rx_gain_override(dev);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFFE);
+ b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0xF7FF);
+ return ret;
}

static void lpphy_calibration(struct b43_wldev *dev)

{
	struct b43_phy_lp *lpphy = dev->phy.lp;
	enum b43_lpphy_txpctl_mode saved_pctl_mode;

+ bool full_cal = false;
+
+ if (lpphy->full_calib_chan != lpphy->channel) {
+ full_cal = true;
+ lpphy->full_calib_chan = lpphy->channel;
+ }

	b43_mac_suspend(dev);

	lpphy_btcoex_override(dev);
+	if (dev->phy.rev >= 2)
+		lpphy_save_dig_flt_state(dev);
	lpphy_read_tx_pctl_mode_from_hardware(dev);
	saved_pctl_mode = lpphy->txpctl_mode;
	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
	//TODO Perform transmit power table I/Q LO calibration
	if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF))
		lpphy_pr41573_workaround(dev);

- //TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration
+ if ((dev->phy.rev >= 2) && full_cal) {
+ lpphy_papd_cal_txpwr(dev);
+ }

	lpphy_set_tx_power_control(dev, saved_pctl_mode);

- //TODO Perform I/Q calibration with a single control value set
+ if (dev->phy.rev >= 2)
+ lpphy_restore_dig_flt_state(dev);
+ lpphy_rx_iq_cal(dev, true, true, false, false, NULL);

	b43_mac_enable(dev);
}
@@ -1532,12 +2075,6 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
}

-static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
- bool blocked)
-{
- //TODO
-}
-

struct b206x_channel {
	u8 channel;
	u16 freq;
@@ -2003,22 +2540,6 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
	return err;
}

-
-/* This was previously called lpphy_japan_filter */
-static void lpphy_set_analog_filter(struct b43_wldev *dev, int channel) -{
- struct b43_phy_lp *lpphy = dev->phy.lp;
- u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter!
-
- if (dev->phy.rev < 2) { //SPEC FIXME Isn't this rev0/1-specific?
- b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFCFF, tmp << 9);
- if ((dev->phy.rev == 1) && (lpphy->rc_cap))
- lpphy_set_rc_cap(dev);
- } else {
- b43_radio_write(dev, B2063_TX_BB_SP3, 0x3F);
- }
-}
-
static void lpphy_b2063_vco_calib(struct b43_wldev *dev)

{
	u16 tmp;
@@ -2203,18 +2724,6 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
	return 0;
}

-static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) -{
- if (dev->phy.rev >= 2)
- return; // rev2+ doesn't support antenna diversity
-
- if (B43_WARN_ON(antenna > B43_ANTENNA_AUTO1))
- return;
-
- b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFD, antenna & 0x2);
- b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFFE, antenna & 0x1);
-}
-
static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)

{
	//TODO
@@ -2227,6 +2736,11 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
	return B43_TXPWR_RES_DONE;
}

+static void b43_lpphy_op_pwork_15sec(struct b43_wldev *dev) +{
+ //TODO
+}
+

const struct b43_phy_operations b43_phyops_lp = {
	.allocate		= b43_lpphy_op_allocate,
	.free			= b43_lpphy_op_free,
@@ -2244,4 +2758,6 @@ const struct b43_phy_operations b43_phyops_lp = {
	.set_rx_antenna		= b43_lpphy_op_set_rx_antenna,
	.recalc_txpower		= b43_lpphy_op_recalc_txpower,
	.adjust_txpower		= b43_lpphy_op_adjust_txpower,

+ .pwork_15sec = b43_lpphy_op_pwork_15sec,
+ .pwork_60sec = lpphy_calibration,
};

drivers/net/wireless/b43/phy_lp.h +0 -0
index c3232c1..62737f7 100644
@@ -286,6 +286,7 @@

#define B43_LPPHY_TR_LOOKUP_6 B43_PHY_OFDM(0xC8) /* TR Lookup 6 */
#define B43_LPPHY_TR_LOOKUP_7 B43_PHY_OFDM(0xC9) /* TR Lookup 7 */
#define B43_LPPHY_TR_LOOKUP_8 B43_PHY_OFDM(0xCA) /* TR Lookup 8 */
+#define B43_LPPHY_RF_PWR_OVERRIDE B43_PHY_OFDM(0xD3) /* RF power override */

@@ -871,12 +872,12 @@ struct b43_phy_lp {
	u8 rssi_gs;

	/* RC cap */
-	u8 rc_cap; /* FIXME initial value? */
+	u8 rc_cap;
	/* BX arch */
	u8 bx_arch;

	/* Full calibration channel */

- u8 full_calib_chan; /* FIXME initial value? */
+ u8 full_calib_chan;

	/* Transmit iqlocal best coeffs */
	bool tx_iqloc_best_coeffs_valid;

@@ -891,6 +892,12 @@ struct b43_phy_lp {

	/* The channel we are tuned to */
	u8 channel;

+
+ /* The active antenna diversity mode */
+ int antenna;
+
+ /* Frequency of the active TX tone */
+ int tx_tone_freq;
};

enum tssi_mux_mode {

Signature · 1 line
1.6.2.4
#1 lore raw

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

Quoted 24 lines
(quoted diff) +24 -0
+	b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xFFF8);
+	lpphy_table_init(dev); //FIXME is table init needed?
+	lpphy_baseband_init(dev);
+	b43_lpphy_op_software_rfkill(dev, false);
+	lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
+	if (dev->phy.rev < 2) {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0x140),
+				     saved_tab_size, saved_tab);
+	} else {
+		b43_lptab_write_bulk(dev, B43_LPTAB32(7, 0x140),
+				     saved_tab_size, saved_tab);
+	}
+	b43_write16(dev, B43_MMIO_CHANNEL, lpphy->channel);
+	lpphy->tssi_npt = tssi_npt;
+	lpphy->tssi_idx = tssi_idx;
+	lpphy_set_analog_filter(dev, lpphy->channel);
+	if (tx_pwr_idx_over != -1)
+		lpphy_set_tx_power_by_index(dev, tx_pwr_idx_over);
+	if (lpphy->rc_cap)
+		lpphy_set_rc_cap(dev);
+	b43_lpphy_op_set_rx_antenna(dev, lpphy->antenna);
+	lpphy_set_tx_power_control(dev, txpctl_mode);
+	kfree(saved_tab);
+}
Signature · 1 line
Greetings, Michael.
#2 lore raw
Quoted 17 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

Quoted 2 lines

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

Larry

#3 lore raw
Quoted 18 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 17 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

Quoted 7 lines
Quoted 2 lines

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

Signature · 1 line
Greetings, Michael.
#4 lore raw
Quoted 22 lines · Michael Buesch
Quoted 21 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 19 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

Quoted 8 lines
Quoted 4 lines

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

So is this patch right or not? Should I hold onto it for 2.6.33 (i.e. after the 2.6.32 merge window)?

John

Signature · 2 lines
John W. Linville		Someday the world will need a hero, and you
[email protected]			might be all we have.  Be ready.
#5 lore raw
Quoted 28 lines · On Monday 31 August 2009 19:53:31 John W. Linville wrote:
Quoted 27 lines · Michael Buesch
Quoted 25 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 17 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

Quoted 2 lines

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

Quoted 6 lines
Quoted 3 lines

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

So is this patch right or not? Should I hold onto it for 2.6.33 (i.e. after the 2.6.32 merge window)?

I'm pretty sure it's incorrect.

Signature · 1 line
Greetings, Michael.
#6 lore raw
Quoted 26 lines · Michael Buesch
Quoted 25 lines · On Monday 31 August 2009 19:53:31 John W. Linville wrote:
Quoted 24 lines · Michael Buesch
Quoted 23 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 16 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

static void lpphy_pr41573_workaround(struct b43_wldev *dev) {

(quoted diff) +1 -0
 	struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
 		b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
 				    saved_tab_size, saved_tab);
 	}
+	b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

Quoted 2 lines

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

So is this patch right or not? Should I hold onto it for 2.6.33 (i.e. after the 2.6.32 merge window)?

I'm pretty sure it's incorrect.

I agree.

Larry

#7 lore raw
In reply to Michael Buesch
Quoted 33 lines · Michael Buesch
Quoted 32 lines · On Monday 31 August 2009 19:53:31 John W. Linville wrote:
Quoted 30 lines · Michael Buesch
Quoted 18 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 17 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

 static void lpphy_pr41573_workaround(struct b43_wldev *dev) {
       struct b43_phy_lp *lpphy = dev->phy.lp;

(quoted diff) +1 -0
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
                b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
                                    saved_tab_size, saved_tab);
        }
+      b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

Quoted 7 lines
Quoted 2 lines

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

Quoted 8 lines
Quoted 2 lines

So is this patch right or not?  Should I hold onto it for 2.6.33 (i.e. after the 2.6.32 merge window)?

I'm pretty sure it's incorrect.

--
Greetings, Michael.

Do we have the correct reset routine implemented somewhere, or is it a new routine to add?

Signature · 1 line
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
#8 lore raw
Quoted 37 lines · On Monday 31 August 2009 21:38:28 Gábor Stefanik wrote:
Quoted 36 lines · Michael Buesch
Quoted 34 lines · On Monday 31 August 2009 19:53:31 John W. Linville wrote:
Quoted 22 lines · Michael Buesch
Quoted 21 lines · On Sunday 30 August 2009 17:10:23 Larry Finger wrote:
Quoted 19 lines · Michael Buesch

Review static void lpphy_pr41573_workaround(struct b43_wldev *dev) · line 1491

Quoted 8 lines · On Sunday 30 August 2009 02:15:55 Gábor Stefanik wrote:

 static void lpphy_pr41573_workaround(struct b43_wldev *dev) {
       struct b43_phy_lp *lpphy = dev->phy.lp;

(quoted diff) +1 -0
@@ -1357,28 +1488,440 @@ static void lpphy_pr41573_workaround(struct b43_wldev *dev)
                b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140),
                                    saved_tab_size, saved_tab);
        }
+      b43_put_phy_into_reset(dev);

Are you sure you really want this?
This function completely disables the PHY on the backplane and keeps the physical PHY reset pin asserted (even after return from the function).
So the PHY will physically be powered down from this point on. The following PHY accesses could even hang the machine, because the PHY won't respond to register accesses anymore.

We currently only use this function on A/G Multi-PHY devices to permanently hard-disable the PHY that's not used.

Quoted 8 lines
Quoted 4 lines

The PHY reset routine in
http://bcm-v4.sipsolutions.net/802.11/PHY/Reset, which I just updated for the latest N PHY changes, appears to be a different routine than b43_put_phy_into_reset(). The names are confusing.

b43_put_phy_into_reset() is opencoded in the specifications in various init routines. There's no separate specs page for that function.
But I think the code is straightforward and easy to understand.

So is this patch right or not?  Should I hold onto it for 2.6.33 (i.e. after the 2.6.32 merge window)?

Quoted 9 lines
Quoted 5 lines

I'm pretty sure it's incorrect.

--
Greetings, Michael.

Do we have the correct reset routine implemented somewhere, or is it a new routine to add?

We opencode something similar (N stuff and so on not included) in wireless_core_reset. So we should probably implement http://bcm-v4.sipsolutions.net/802.11/PHY/Reset
in a separate function and also call that from wireless_core_reset (and your workaround code).

Signature · 1 line
Greetings, Michael.