* Re: Multiple SSID
From: Ben Greear @ 2009-08-12 17:59 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Stephen Hemminger, John W. Linville, Johannes Berg,
linux-wireless
In-Reply-To: <43e72e890908121025p75b141b6o86c30518bf9de7ea@mail.gmail.com>
On 08/12/2009 10:25 AM, Luis R. Rodriguez wrote:
> On Wed, Aug 12, 2009 at 10:04 AM, Stephen
> Hemminger<shemminger@vyatta.com> wrote:
>> I have a dumb questions. How does one setup multiple SSID's with
>> current (ie not madwifi) wireless API?
> Anyway I believe AP-enabled devices right now only support creating 1
> AP interfface. I believe the exception to this right now is ath9k
> through the private virtual interface stuff Jouni created, but to be
> honest I have to go and review that to make sure you can create 2 APs.
We're *still* working on virtualizing ath5k. Over the last few days,
we have gotten this working pretty well, including virtual APs, virtual STAs with
WPA & no security. I haven't tested WEP lately.
We are chasing a few remaining buglets and optimizations currently.
I have a page up here to help get started using this:
http://www.candelatech.com/oss/vsta.html
NOTE: The .31 tree mentioned there has a bunch of other patches in it
that we use for various purposes. There is no clean way to get *just*
our wifi changes at this point.
We plan to submit the patches upstream, but there is a lot of churn in wifi code
so it will be a bit longer before we can get the patches tested on stable
code and then ported to the development branches.
I haven't tried out ath9k yet, but look forward to it once we get
ath5k nailed down.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH] b43: Implement RC calibration for rev.0/1 LP-PHYs
From: Gábor Stefanik @ 2009-08-12 17:56 UTC (permalink / raw)
To: John Linville, Michael Buesch, Larry Finger
Cc: Broadcom Wireless, linux-wireless
Also implement get/set BB mult, get/set TX gain, set RX gain,
disable/restore CRS, run/stop DDFS, RX IQ est and QDIV roundup
in the process.
Signed-off-by: Gábor Stefanik <netrolller.3d@gmail.com>
---
Larry, please review the "SPEC FIXME" comments!
drivers/net/wireless/b43/phy_lp.c | 414 ++++++++++++++++++++++++++++++++++++-
1 files changed, 413 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 689c932..b283b58 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -605,6 +605,8 @@ static void lpphy_radio_init(struct b43_wldev *dev)
}
}
+struct lpphy_iq_est { u32 iq_prod, i_pwr, q_pwr; };
+
static void lpphy_set_rc_cap(struct b43_wldev *dev)
{
u8 rc_cap = dev->phy.lp->rc_cap;
@@ -614,9 +616,419 @@ static void lpphy_set_rc_cap(struct b43_wldev *dev)
b43_radio_write(dev, B2062_S_RXG_CNT16, ((rc_cap & 0x1F) >> 2) | 0x80);
}
+static u8 lpphy_get_bb_mult(struct b43_wldev *dev)
+{
+ return (b43_lptab_read(dev, B43_LPTAB16(0, 87)) & 0xFF00) >> 8;
+}
+
+static void lpphy_set_bb_mult(struct b43_wldev *dev, u8 bb_mult)
+{
+ b43_lptab_write(dev, B43_LPTAB16(0, 87), (u16)bb_mult << 8);
+}
+
+static void lpphy_disable_crs(struct b43_wldev *dev)
+{
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x80);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFC, 0x1);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x3);
+ 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_0, 0xFFF7);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x10);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x10);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFDF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x20);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFBF);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x40);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x7);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x38);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0x100);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL0, 0);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL1, 1);
+ b43_phy_write(dev, B43_LPPHY_PS_CTL_OVERRIDE_VAL2, 0x20);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF);
+ b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45AF);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, 0x3FF);
+}
+
+static void lpphy_restore_crs(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x60);
+ else
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xFF1F, 0x20);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFF80);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFC00);
+}
+
+struct lpphy_tx_gains { u16 gm, pga, pad, dac; };
+
+static struct lpphy_tx_gains lpphy_get_tx_gains(struct b43_wldev *dev)
+{
+ struct lpphy_tx_gains gains;
+ u16 tmp;
+
+ gains.dac = (b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0x380) >> 7;
+ if (dev->phy.rev < 2) {
+ tmp = b43_phy_read(dev,
+ B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7FF;
+ gains.gm = tmp & 0x0007;
+ gains.pga = (tmp & 0x0078) >> 3;
+ gains.pad = (tmp & 0x780) >> 7;
+ } else {
+ tmp = b43_phy_read(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL);
+ gains.pad = b43_phy_read(dev, B43_PHY_OFDM(0xFB)) & 0xFF;
+ gains.gm = tmp & 0xFF;
+ gains.pga = (tmp>>8) & 0xFF;
+ }
+
+ return gains;
+}
+
+static void lpphy_set_dac_gain(struct b43_wldev *dev, u16 dac)
+{
+ u16 ctl = b43_phy_read(dev, B43_LPPHY_AFE_DAC_CTL) & 0xC7F;
+ ctl |= dac << 7;
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DAC_CTL, 0xF000, ctl);
+}
+
+static void lpphy_set_tx_gains(struct b43_wldev *dev,
+ struct lpphy_tx_gains gains)
+{
+ u16 rf_gain, pa_gain;
+
+ if (dev->phy.rev < 2) {
+ rf_gain = (gains.pad << 7) | (gains.pga << 3) | gains.gm;
+ 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)) & 0x7F00;
+ b43_phy_write(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ (gains.pga << 8) | gains.gm);
+ b43_phy_maskset(dev, B43_LPPHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ 0x8000, gains.pad | pa_gain);
+ b43_phy_write(dev, B43_PHY_OFDM(0xFC),
+ (gains.pga << 8) | gains.gm);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xFD),
+ 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_RF_OVERRIDE_2, 0xFFBF, 1<<4);
+}
+
+static void lpphy_rev0_1_set_rx_gain(struct b43_wldev *dev, u32 gain)
+{
+ u16 trsw = gain & 0x1;
+ u16 lna = (gain & 0xFFFC) | ((gain & 0xC) >> 2);
+ u16 ext_lna = (gain & 2) >> 1;
+
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF, ext_lna<<10);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xF7FF, ext_lna<<11);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
+}
+
+static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
+{
+ u16 low_gain = gain & 0xFFFF;
+ u16 high_gain = (gain >> 16) & 0xF;
+ u16 ext_lna = (gain >> 21) & 0x1;
+ u16 trsw = ~(gain >> 21) & 0x1;
+ u16 tmp;
+ //SPEC FIXME is trsw really just ~(bool)ext_lna for rev2+?
+
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0xFFFE, trsw);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFDFF, ext_lna<<9);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFBFF, ext_lna<<10);
+ b43_phy_write(dev, B43_LPPHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF0, high_gain);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ tmp = (gain >> 2) & 0x3;
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL,
+ 0xE7FF, tmp<<11);
+ b43_phy_maskset(dev, B43_PHY_OFDM(0xE6), 0xFFE7, tmp<<3);
+ }
+}
+
+static void lpphy_enable_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)
+ return;
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFBFF);
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFFF7);
+ } else {
+ b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
+ }
+}
+
+static void lpphy_disable_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)
+ return;
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 0x400);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_2, 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)
+ lpphy_rev0_1_set_rx_gain(dev, gain);
+ else
+ lpphy_rev2plus_set_rx_gain(dev, gain);
+ lpphy_enable_rx_gain_override(dev);
+}
+
+static void lpphy_set_rx_gain_by_index(struct b43_wldev *dev, u16 idx)
+{
+ u32 gain = b43_lptab_read(dev, B43_LPTAB16(12, idx));
+ lpphy_set_rx_gain(dev, gain);
+}
+
+static void lpphy_stop_ddfs(struct b43_wldev *dev)
+{
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFD);
+ b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0xFFDF);
+}
+
+static void lpphy_run_ddfs(struct b43_wldev *dev, int i_on, int q_on,
+ int incr1, int incr2, int scale_idx)
+{
+ lpphy_stop_ddfs(dev);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0xFF80);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS_POINTER_INIT, 0x80FF);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0xFF80, incr1);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS_INCR_INIT, 0x80FF, incr2 << 3);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFF7, i_on << 3);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFFEF, q_on << 4);
+ b43_phy_maskset(dev, B43_LPPHY_AFE_DDFS, 0xFF9F, scale_idx << 5);
+ b43_phy_mask(dev, B43_LPPHY_AFE_DDFS, 0xFFFB);
+ b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x2);
+ b43_phy_set(dev, B43_LPPHY_AFE_DDFS, 0x20);
+}
+
+static bool lpphy_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time,
+ struct lpphy_iq_est *iq_est)
+{
+ int i;
+
+ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFF7);
+ b43_phy_write(dev, B43_LPPHY_IQ_NUM_SMPLS_ADDR, samples);
+ b43_phy_maskset(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFF00, time);
+ b43_phy_mask(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFEFF);
+ b43_phy_set(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xFDFF);
+
+ for (i = 0; i < 500; i++) {
+ if (!(b43_phy_read(dev,
+ B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
+ break;
+ msleep(1);
+ }
+
+ if ((b43_phy_read(dev, B43_LPPHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
+ return false;
+ }
+
+ iq_est->iq_prod = b43_phy_read(dev, B43_LPPHY_IQ_ACC_HI_ADDR);
+ iq_est->iq_prod <<= 16;
+ iq_est->iq_prod |= b43_phy_read(dev, B43_LPPHY_IQ_ACC_LO_ADDR);
+
+ iq_est->i_pwr = b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_HI_ADDR);
+ iq_est->i_pwr <<= 16;
+ iq_est->i_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_I_PWR_ACC_LO_ADDR);
+
+ iq_est->q_pwr = b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_HI_ADDR);
+ iq_est->q_pwr <<= 16;
+ iq_est->q_pwr |= b43_phy_read(dev, B43_LPPHY_IQ_Q_PWR_ACC_LO_ADDR);
+
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x8);
+ return true;
+}
+
+static int lpphy_loopback(struct b43_wldev *dev)
+{
+ struct lpphy_iq_est iq_est;
+ int i, index = -1;
+ u32 tmp;
+
+ 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);
+ 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);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x8);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x8);
+ b43_radio_write(dev, B2062_N_TX_CTL_A, 0x80);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_0, 0x80);
+ b43_phy_set(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, 0x80);
+ for (i = 0; i < 32; i++) {
+ lpphy_set_rx_gain_by_index(dev, i);
+ lpphy_run_ddfs(dev, 1, 1, 5, 5, 0);
+ if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
+ continue;
+ tmp = (iq_est.i_pwr + iq_est.q_pwr) / 1000;
+ if ((tmp > 4000) && (tmp < 10000)) {
+ index = i;
+ break;
+ }
+ }
+ lpphy_stop_ddfs(dev);
+ return index;
+}
+
+u32 lpphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
+{
+ u32 quotient, remainder, rbit, roundup, tmp;
+
+ if (divisor == 0) {
+ quotient = 0;
+ remainder = 0;
+ } else {
+ quotient = dividend / divisor;
+ remainder = dividend % divisor;
+ }
+
+ rbit = divisor & 0x1;
+ roundup = (divisor >> 1) + rbit;
+ precision--;
+
+ while (precision != 0xFF) {
+ tmp = remainder - roundup;
+ quotient <<= 1;
+ remainder <<= 1;
+ if (remainder >= roundup) {
+ remainder = (tmp << 1) + rbit;
+ quotient--;
+ }
+ precision--;
+ }
+
+ if (remainder >= roundup)
+ quotient++;
+
+ return quotient;
+}
+
+static void lpphy_set_tx_power_control(struct b43_wldev *dev,
+ enum b43_lpphy_txpctl_mode mode);
+
static void lpphy_rev0_1_rc_calib(struct b43_wldev *dev)
{
- //TODO and SPEC FIXME
+ u32 ideal_pwr_table[22] = {
+ 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
+ 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
+ 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
+ 0x0004c, 0x0002c, 0x0001a, 0xc0006,
+ };
+ bool old_txg_ovr;
+ u16 old_rf_ovr, old_rf_ovrval, old_afe_ovr, old_afe_ovrval,
+ old_rf2_ovr, old_rf2_ovrval, old_phy_ctl, old_txpctl;
+ u8 old_bbmult;
+ struct lpphy_iq_est iq_est;
+ struct lpphy_tx_gains tx_gains;
+ struct b43_phy_lp *lpphy = dev->phy.lp;
+ int loopback, i, j, inner_sum;
+ u32 normal_pwr, ideal_pwr, mean_sq_pwr, tmp = 0, mean_sq_pwr_min = 0;
+
+ memset(&iq_est, 0, sizeof(iq_est));
+
+ b43_switch_channel(dev, 7);
+ old_txg_ovr = (b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR) >> 6) & 1;
+ old_bbmult = lpphy_get_bb_mult(dev);
+ if (old_txg_ovr)
+ tx_gains = lpphy_get_tx_gains(dev);
+ old_rf_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_0);
+ old_rf_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_VAL_0);
+ old_afe_ovr = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVR);
+ old_afe_ovrval = b43_phy_read(dev, B43_LPPHY_AFE_CTL_OVRVAL);
+ old_rf2_ovr = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2);
+ old_rf2_ovrval = b43_phy_read(dev, B43_LPPHY_RF_OVERRIDE_2_VAL);
+ old_phy_ctl = b43_phy_read(dev, B43_LPPHY_LP_PHY_CTL);
+ old_txpctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD) &
+ B43_LPPHY_TX_PWR_CTL_CMD_MODE;
+
+ lpphy_set_tx_power_control(dev, B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF);
+ lpphy_disable_crs(dev);
+ loopback = lpphy_loopback(dev);
+ if (loopback == -1)
+ goto finish;
+ lpphy_set_rx_gain_by_index(dev, loopback);
+ b43_phy_maskset(dev, B43_LPPHY_LP_PHY_CTL, 0xFFBF, 0x40);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFF8, 0x1);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFFC7, 0x8);
+ b43_phy_maskset(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, 0xFF3F, 0xC0);
+ for (i = 128; i <= 159; i++) {
+ b43_radio_write(dev, B2062_N_RXBB_CALIB2, i);
+ inner_sum = 0;
+ for (j = 5; j <= 25; j++) {
+ lpphy_run_ddfs(dev, 1, 1, j, j, 0);
+ if (!(lpphy_rx_iq_est(dev, 1000, 32, &iq_est)))
+ goto finish;
+ mean_sq_pwr = iq_est.i_pwr + iq_est.q_pwr;
+ if (j == 5)
+ tmp = mean_sq_pwr;
+ ideal_pwr = ((ideal_pwr_table[j-5] >> 3) + 1) >> 1;
+ normal_pwr = lpphy_qdiv_roundup(mean_sq_pwr, tmp, 12);
+ mean_sq_pwr = ideal_pwr - normal_pwr;
+ mean_sq_pwr *= mean_sq_pwr;
+ inner_sum += mean_sq_pwr;
+ if ((i = 128) || (inner_sum < mean_sq_pwr_min)) {
+ lpphy->rc_cap = i;
+ mean_sq_pwr_min = inner_sum;
+ }
+ }
+ }
+ lpphy_stop_ddfs(dev);
+
+finish:
+ lpphy_restore_crs(dev);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_VAL_0, old_rf_ovrval);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_0, old_rf_ovr);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVRVAL, old_afe_ovrval);
+ b43_phy_write(dev, B43_LPPHY_AFE_CTL_OVR, old_afe_ovr);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2_VAL, old_rf2_ovrval);
+ b43_phy_write(dev, B43_LPPHY_RF_OVERRIDE_2, old_rf2_ovr);
+ b43_phy_write(dev, B43_LPPHY_LP_PHY_CTL, old_phy_ctl);
+
+ lpphy_set_bb_mult(dev, old_bbmult);
+ if (old_txg_ovr)
+ /*
+ * SPEC FIXME: The specs say "get_tx_gains" here, which is
+ * illogical. According to lwfinger, vendor driver v4.150.10.5
+ * has a Set here, while v4.174.64.19 has a Get - regression in
+ * the vendor driver? This should be tested this once the code
+ * is testable.
+ */
+ lpphy_set_tx_gains(dev, tx_gains);
+ lpphy_set_tx_power_control(dev, old_txpctl);
+ if (lpphy->rc_cap)
+ lpphy_set_rc_cap(dev);
}
static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
--
1.6.2.4
^ permalink raw reply related
* Re: [PATCH 3/3] ath5k: use bit shift operators for cache line size
From: Bob Copeland @ 2009-08-12 17:50 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless, ath9k-devel, ath5k-devel
In-Reply-To: <43e72e890908121032u52ed53f5u5835dd73d83f8871@mail.gmail.com>
On Wed, Aug 12, 2009 at 1:32 PM, Luis R.
Rodriguez<lrodriguez@atheros.com> wrote:
>>> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
>>> index 63c2b57..2b3cf39 100644
>>> --- a/drivers/net/wireless/ath/ath5k/base.c
>>> +++ b/drivers/net/wireless/ath/ath5k/base.c
>>> @@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
>>> * DMA to work so force a reasonable value here if it
>>> * comes up zero.
>>> */
>>> - csz = L1_CACHE_BYTES / sizeof(u32);
>>> + csz = L1_CACHE_BYTES >> 2;
>>> pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
>>
>> I'm not sure it's better,
>
> I did this for consistency between drivers but yes the advantage with
> a shift is it should be cheaper than a multiplication. Although I am
> not sure if simple multiplications get optimized by either the
> compiler or an architecture to shifts.
It shouldn't matter in the above case -- division by two constants.
In the multiplication by power of 2 constant case, it should also
get optimized by the compiler. '>> 2' looks like magic though, maybe
a comment to say why?
>> although the whole thing seems bogus to
>> me. Is there really a modern machine where PCI cache line size should
>> only be four bytes?
To correct above, I misread what it was doing.. it's getting cpu cache
size and dividing by 4 to get the number of words, if cache line size
was zeroed initially. Ok, I'll go back to sleep now.
Whether needed or not, there's a lot of confusing comments and
voodoo around the stuff (something about 2.4 kernels...) that would
be nice to clear up.
> Whether we remove this though would be a change which should go
> through a separate patch I think.
Yeah, that's reasonable.
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* Re: Multiple SSID
From: Johannes Berg @ 2009-08-12 17:35 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: Stephen Hemminger, John W. Linville, linux-wireless
In-Reply-To: <43e72e890908121025p75b141b6o86c30518bf9de7ea@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1039 bytes --]
On Wed, 2009-08-12 at 10:25 -0700, Luis R. Rodriguez wrote:
> On Wed, Aug 12, 2009 at 10:04 AM, Stephen
> Hemminger<shemminger@vyatta.com> wrote:
> > I have a dumb questions. How does one setup multiple SSID's with
> > current (ie not madwifi) wireless API?
> >
> > 1. I assume need to run multiple instances of hostapd with different
> > config. Will that work?
>
> Yes. But the next question is how to create new wlan%d AP interfaces.
> That is answered below.
Huh, no, that's not really true. You can run one hostapd with multiple
BSSes, in theory, except driver_nl80211.c doesn't have all the code for
it yet. Should be fairly simple though to implement, just needs a list
of BSSes in that file.
> > 3. Do vlan's work on wireless (ath9k)?
Well, not in the 802.1q sense. VLANs exist our terminology as a way to
separate (by using different group keys and different local netdevs)
stations connected to the same BSS. This should work, with radius or
with static configuration, but I never tried.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: Libertas: Association request to the driver failed
From: Dan Williams @ 2009-08-12 17:34 UTC (permalink / raw)
To: John W. Linville
Cc: Roel Kluin, Daniel Mack, libertas-dev, linux-wireless,
linux-kernel
In-Reply-To: <1250093737.31650.17.camel@localhost.localdomain>
On Wed, 2009-08-12 at 11:15 -0500, Dan Williams wrote:
> On Tue, 2009-08-11 at 14:24 -0400, John W. Linville wrote:
> > Comments from the libertas crowd? This seems a bit long for this
> > part of the cycle.
> >
> > Should we just revert the original patch, then reapply it with this
> > one for 2.6.32?
>
> I'd feel more comfortable with that. Roel did find a real problem, but
> we need to make sure the fix doesn't break stuff since it appears the
> rate code is more complicated than we thought.
Well, OK, it's not complicated, just obfuscated.
mrvl_ie_rates_param_set is a TLV structure, and the size of the overall
structure from 'header' will tell how many rates there actually are
following the header. The [1] is left over from the vendor driver. If
that's confusing things, can we just use [0] here or does the scanner
that found this need to be fixed? We'll certainly be pointing past the
end of the mrvl_ie_rates_param_set, but we won't be accessing beyond
memory we don't control, since the mrvl_ie_rates_param_set will always
point into a buffer (from kzalloc) that's large enough. Rates is also
never used late enough in the command spacing to be at risk of
overrunning the end of the command buffer into which it points.
The following (not runtime tested) should make it clearer what's going
on, though it doesn't address the [1]/[0] issue:
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 1902b6f..8c05388 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -35,7 +35,8 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*
* @param priv A pointer to struct lbs_private structure
* @param rates the buffer which keeps input and output
- * @param rates_size the size of rate1 buffer; new size of buffer on return
+ * @param rates_size the size of rates buffer; new size of buffer on return,
+ * which will be less than or equal to original rates_size
*
* @return 0 on success, or -1 on error
*/
@@ -43,39 +44,42 @@ static int get_common_rates(struct lbs_private *priv,
u8 *rates,
u16 *rates_size)
{
- u8 *card_rates = lbs_bg_rates;
- int ret = 0, i, j;
- u8 tmp[(ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1)];
- size_t tmp_size = 0;
-
- /* For each rate in card_rates that exists in rate1, copy to tmp */
- for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
- for (j = 0; j < *rates_size && rates[j]; j++) {
- if (rates[j] == card_rates[i])
- tmp[tmp_size++] = card_rates[i];
+ int i, j;
+ u8 intersection[MAX_RATES];
+ u16 intersection_size;
+ u16 num_rates = 0;
+
+ intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
+
+ /* Allow each rate from 'rates' that is supported by the hardware */
+ for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
+ for (j = 0; j < intersection_size && rates[j]; j++) {
+ if (rates[j] == lbs_bg_rates[i])
+ intersection[num_rates++] = rates[j];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates,
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
ARRAY_SIZE(lbs_bg_rates));
- lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+ lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->enablehwauto) {
- for (i = 0; i < tmp_size; i++) {
- if (tmp[i] == priv->cur_rate)
+ for (i = 0; i < num_rates; i++) {
+ if (intersection[i] == priv->cur_rate)
goto done;
}
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
- ret = -1;
+ return -1;
}
+
done:
memset(rates, 0, *rates_size);
- *rates_size = min_t(int, tmp_size, *rates_size);
- memcpy(rates, tmp, *rates_size);
- return ret;
+ *rates_size = num_rates;
+ memcpy(rates, intersection, num_rates);
+ return 0;
}
@@ -317,8 +321,8 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
- memcpy(&rates->rates, &bss->rates, MAX_RATES);
- tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
+ tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
+ memcpy(&rates->rates, &bss->rates, tmplen);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@@ -592,7 +596,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
+ ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
^ permalink raw reply related
* Re: [PATCH 3/3] ath5k: use bit shift operators for cache line size
From: Luis R. Rodriguez @ 2009-08-12 17:32 UTC (permalink / raw)
To: Bob Copeland; +Cc: linville, linux-wireless, ath9k-devel, ath5k-devel
In-Reply-To: <b6c5339f0908121013v4316cfdbsf4e274217555dbe9@mail.gmail.com>
On Wed, Aug 12, 2009 at 10:13 AM, Bob Copeland<me@bobcopeland.com> wrote:
> On Wed, Aug 12, 2009 at 12:57 PM, Luis R.
> Rodriguez<lrodriguez@atheros.com> wrote:
>> This matches ath9k, providing consistency when reading both drivers.
>>
>> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
>> ---
>> drivers/net/wireless/ath/ath5k/base.c | 4 ++--
>> 1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
>> index 63c2b57..2b3cf39 100644
>> --- a/drivers/net/wireless/ath/ath5k/base.c
>> +++ b/drivers/net/wireless/ath/ath5k/base.c
>> @@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
>> * DMA to work so force a reasonable value here if it
>> * comes up zero.
>> */
>> - csz = L1_CACHE_BYTES / sizeof(u32);
>> + csz = L1_CACHE_BYTES >> 2;
>> pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
>
> I'm not sure it's better,
I did this for consistency between drivers but yes the advantage with
a shift is it should be cheaper than a multiplication. Although I am
not sure if simple multiplications get optimized by either the
compiler or an architecture to shifts.
> although the whole thing seems bogus to
> me. Is there really a modern machine where PCI cache line size should
> only be four bytes?
Beats me, I was just matching the code for ath9k. The whole cache
alignment practice seems to be debatable to me and and hoping Sam
Leffer might recall the exact reasonings behind it.
Whether we remove this though would be a change which should go
through a separate patch I think.
Luis
^ permalink raw reply
* Re: [ath5k-devel] [PATCH 0/3] ath: advance ath.ko with one more helper
From: Luis R. Rodriguez @ 2009-08-12 17:27 UTC (permalink / raw)
To: Bob Copeland; +Cc: ath5k-devel, ath9k-devel, linux-wireless, linville
In-Reply-To: <b6c5339f0908121021x3bc9fe26vb17532de6c464b7f@mail.gmail.com>
On Wed, Aug 12, 2009 at 10:21 AM, Bob Copeland<me@bobcopeland.com> wrote:
> On Wed, Aug 12, 2009 at 12:56 PM, Luis R.
> Rodriguez<lrodriguez@atheros.com> wrote:
>> This adds a common structure where we can start stuffing shared items
>> and introduces a helper for both ath5k and ath9k's use.
>>
>> Luis R. Rodriguez (3):
>> ath: add common ath_rxbuf_alloc() and make ath9k use it
>> ath5k: use common ath.ko ath_rxbuf_alloc()
>> ath5k: use bit shift operators for cache line size
>
> Series looks OK to me but I think we can add a 4/4 that would:
>
> - include ath/reg.h [don't remember if that's the name right now]
> in ath.h
> - move reg structs into ath_common (although, this could be a
> bad call for ar9170, haven't really checked).
>
> Then we only have to deal with one header and one composite struct
> (for now) as the interface between the modules.
Sure, I was thinking of doing this after this. Is that acceptable?
Luis
^ permalink raw reply
* Re: Multiple SSID
From: Luis R. Rodriguez @ 2009-08-12 17:25 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: John W. Linville, Johannes Berg, linux-wireless
In-Reply-To: <20090812100416.744dc5ba@nehalam>
On Wed, Aug 12, 2009 at 10:04 AM, Stephen
Hemminger<shemminger@vyatta.com> wrote:
> I have a dumb questions. How does one setup multiple SSID's with
> current (ie not madwifi) wireless API?
>
> 1. I assume need to run multiple instances of hostapd with different
> config. Will that work?
Yes. But the next question is how to create new wlan%d AP interfaces.
That is answered below.
> 2. Since IP address is attached to device (wlan0), how can each SSID
> have different IP address? Use vlan's?
The new 'iw' [2] utility could be used to create monitor interfaces or
ad-hoc interfaces for example. We decided to only allow you to create
an "AP" type of interface with a utility that handles the MLME in
userspace, such a utility is hostapd. You will need to use the nl80211
driver with hosatpd [2]. We have documented the supported wireless
modes in our wiki [3], I suppose that could use some updating.
Anyway I believe AP-enabled devices right now only support creating 1
AP interfface. I believe the exception to this right now is ath9k
through the private virtual interface stuff Jouni created, but to be
honest I have to go and review that to make sure you can create 2 APs.
Typically drivers (MadWifi) which supported multiple BSSs (therefore
with two SSIDs) would allow you to do this by creating BSSes on the
same channel. The ath9k virtual interface thing allows you to create
interfaces on *separate* channels, and provides its own scheduler,
which you can tune, for switching back and forth.
[1] http://wireless.kernel.org/en/users/Documentation/iw
[2] http://wireless.kernel.org/en/users/Documentation/hostapd
[3] http://wireless.kernel.org/en/users/Documentation/modes
> 3. Do vlan's work on wireless (ath9k)?
Not sure what is required to support vlans.
Luis
^ permalink raw reply
* Re: [PATCH 0/3] ath: advance ath.ko with one more helper
From: Bob Copeland @ 2009-08-12 17:21 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless, ath9k-devel, ath5k-devel
In-Reply-To: <1250096221-11000-1-git-send-email-lrodriguez@atheros.com>
On Wed, Aug 12, 2009 at 12:56 PM, Luis R.
Rodriguez<lrodriguez@atheros.com> wrote:
> This adds a common structure where we can start stuffing shared items
> and introduces a helper for both ath5k and ath9k's use.
>
> Luis R. Rodriguez (3):
> ath: add common ath_rxbuf_alloc() and make ath9k use it
> ath5k: use common ath.ko ath_rxbuf_alloc()
> ath5k: use bit shift operators for cache line size
Series looks OK to me but I think we can add a 4/4 that would:
- include ath/reg.h [don't remember if that's the name right now]
in ath.h
- move reg structs into ath_common (although, this could be a
bad call for ar9170, haven't really checked).
Then we only have to deal with one header and one composite struct
(for now) as the interface between the modules.
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* Re: [PATCH 3/3] ath5k: use bit shift operators for cache line size
From: Bob Copeland @ 2009-08-12 17:13 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linville, linux-wireless, ath9k-devel, ath5k-devel
In-Reply-To: <1250096221-11000-4-git-send-email-lrodriguez@atheros.com>
On Wed, Aug 12, 2009 at 12:57 PM, Luis R.
Rodriguez<lrodriguez@atheros.com> wrote:
> This matches ath9k, providing consistency when reading both drivers.
>
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
> ---
> drivers/net/wireless/ath/ath5k/base.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
> index 63c2b57..2b3cf39 100644
> --- a/drivers/net/wireless/ath/ath5k/base.c
> +++ b/drivers/net/wireless/ath/ath5k/base.c
> @@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
> * DMA to work so force a reasonable value here if it
> * comes up zero.
> */
> - csz = L1_CACHE_BYTES / sizeof(u32);
> + csz = L1_CACHE_BYTES >> 2;
> pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
I'm not sure it's better, although the whole thing seems bogus to
me. Is there really a modern machine where PCI cache line size should
only be four bytes?
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* [PATCH 2.6.31-rc5] Staging: rt2870: new USB ID for Belkin N+ F5D8055
From: Daniele Napolitano @ 2009-08-12 16:59 UTC (permalink / raw)
To: linux-wireless, gregkh, akpm, greg
In-Reply-To: <15d0b9b20908120920sa42235ft4ce0daed4e4f0130@mail.gmail.com>
New USB ID for Belkin N+ F5D8055 (USB 802.11n adapter).
I've made this patch with drivers/staging branch found here:
http://git.kernel.org/?p=linux/kernel/git/gregkh/staging-2.6.git
Signed-off-by: Daniele Napolitano <dnax88@gmail.com>
--- drivers/staging/rt2870/rt2870.h 2009-08-12 18:06:42.606925649 +0200
+++ drivers/staging/rt2870/rt2870.h~ 2009-08-12 18:07:11.698931370 +0200
@@ -102,6 +102,7 @@
{USB_DEVICE(0x14B2,0x3C12)}, /* AL */ \
{USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \
{USB_DEVICE(0x050D,0x815C)}, /* Belkin */ \
+ {USB_DEVICE(0x050D,0x825a)}, /* Belkin */ \
{USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \
{USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \
{USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \
^ permalink raw reply
* [PATCH] ath5k: fix requested allocated RX skb size for DMA
From: Luis R. Rodriguez @ 2009-08-12 16:58 UTC (permalink / raw)
To: linville
Cc: linux-wireless, ath9k-devel, ath5k-devel, Luis R. Rodriguez,
Jiri Slaby, Nick Kossifidis, Bob Copeland
When we dev_alloc_skb() our RX buffers we were asking
for them to be of size:
sc->rxbufsize + sc->common.cachelsz - 1
but when mapping processor virtual memeory for access by the
hardware we were only giving it the sc->rxbufsize, therefore
always preventing the device from accessing the fully allocated
skb.
This patch fixes the disparity. It is unclear to me if there are
other consequences to having this mismatch other than perhaps never
allowing the device to use the full capacity of the allocated skb.
Cc: Jiri Slaby <jirislaby@gmail.com>
Cc: Nick Kossifidis <mickflemm@gmail.com>
Cc: Bob Copeland <me@bobcopeland.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath/ath5k/base.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 2b3cf39..75843f2 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1157,17 +1157,18 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
* fake physical layer header at the start.
*/
skb = ath_rxbuf_alloc(&sc->common,
- sc->rxbufsize + sc->common.cachelsz - 1,
+ sc->rxbufsize,
GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + sc->common.cachelsz - 1);
+ sc->rxbufsize);
return NULL;
}
*skb_addr = pci_map_single(sc->pdev,
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
+
if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
dev_kfree_skb(skb);
@@ -1607,9 +1608,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
int ret;
sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
+ sc->rxbufsize += sc->common.cachelsz - 1;
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- sc->common.cachelsz, sc->rxbufsize);
+ sc->common.cachelsz, sc->rxbufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 3/3] ath5k: use bit shift operators for cache line size
From: Luis R. Rodriguez @ 2009-08-12 16:57 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, ath9k-devel, ath5k-devel, Luis R. Rodriguez
In-Reply-To: <1250096221-11000-1-git-send-email-lrodriguez@atheros.com>
This matches ath9k, providing consistency when reading both drivers.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath/ath5k/base.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 63c2b57..2b3cf39 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -471,7 +471,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
* DMA to work so force a reasonable value here if it
* comes up zero.
*/
- csz = L1_CACHE_BYTES / sizeof(u32);
+ csz = L1_CACHE_BYTES >> 2;
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
}
/*
@@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
__set_bit(ATH_STAT_INVALID, sc->status);
sc->iobase = mem; /* So we can unmap it on detach */
- sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */
+ sc->common.cachelsz = csz << 2; /* convert to bytes */
sc->opmode = NL80211_IFTYPE_STATION;
sc->bintval = 1000;
mutex_init(&sc->lock);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/3] ath5k: use common ath.ko ath_rxbuf_alloc()
From: Luis R. Rodriguez @ 2009-08-12 16:57 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, ath9k-devel, ath5k-devel, Luis R. Rodriguez
In-Reply-To: <1250096221-11000-1-git-send-email-lrodriguez@atheros.com>
Now that its shared we can remove ath5k's own implementation.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath/ath5k/base.c | 21 +++++++--------------
drivers/net/wireless/ath/ath5k/base.h | 3 ++-
2 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index acbcfc2..63c2b57 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -544,7 +544,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
__set_bit(ATH_STAT_INVALID, sc->status);
sc->iobase = mem; /* So we can unmap it on detach */
- sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
+ sc->common.cachelsz = csz * sizeof(u32); /* convert to bytes */
sc->opmode = NL80211_IFTYPE_STATION;
sc->bintval = 1000;
mutex_init(&sc->lock);
@@ -1151,27 +1151,20 @@ static
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
{
struct sk_buff *skb;
- unsigned int off;
/*
* Allocate buffer with headroom_needed space for the
* fake physical layer header at the start.
*/
- skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
+ skb = ath_rxbuf_alloc(&sc->common,
+ sc->rxbufsize + sc->common.cachelsz - 1,
+ GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + sc->cachelsz - 1);
+ sc->rxbufsize + sc->common.cachelsz - 1);
return NULL;
}
- /*
- * Cache-line-align. This is important (for the
- * 5210 at least) as not doing so causes bogus data
- * in rx'd frames.
- */
- off = ((unsigned long)skb->data) % sc->cachelsz;
- if (off != 0)
- skb_reserve(skb, sc->cachelsz - off);
*skb_addr = pci_map_single(sc->pdev,
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
@@ -1613,10 +1606,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
struct ath5k_buf *bf;
int ret;
- sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
+ sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- sc->cachelsz, sc->rxbufsize);
+ sc->common.cachelsz, sc->rxbufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 667bd9d..25a72a8 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -50,6 +50,7 @@
#include "ath5k.h"
#include "debug.h"
+#include "../ath.h"
#define ATH_RXBUF 40 /* number of RX buffers */
#define ATH_TXBUF 200 /* number of TX buffers */
@@ -112,6 +113,7 @@ struct ath5k_rfkill {
* associated with an instance of a device */
struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
+ struct ath_common common;
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
@@ -134,7 +136,6 @@ struct ath5k_softc {
struct ath5k_desc *desc; /* TX/RX descriptors */
dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */
- u16 cachelsz; /* cache line size */
DECLARE_BITMAP(status, 5);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
--
1.6.3.3
^ permalink raw reply related
* [PATCH 1/3] ath: add common ath_rxbuf_alloc() and make ath9k use it
From: Luis R. Rodriguez @ 2009-08-12 16:56 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, ath9k-devel, ath5k-devel, Luis R. Rodriguez
In-Reply-To: <1250096221-11000-1-git-send-email-lrodriguez@atheros.com>
Turns out ath5k and ath9k can share the same helper to
allocates RX skbs. We allocate skbs aligned to the cache line
size. This requirement seems to have come from AR5210; when
this was not done it seems sometimes we'd get bogus data. I'm
also told it may have been a performance enhancement
consideration. In the end I can't be sure we can remove this
on new hardware so just keep this and start sharing it through
ath.ko.
Make ath9k start using this, ath5k is next.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/ath/Kconfig | 4 +--
drivers/net/wireless/ath/ath.h | 30 ++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-
drivers/net/wireless/ath/ath9k/main.c | 2 +-
drivers/net/wireless/ath/ath9k/recv.c | 40 +++----------------------------
drivers/net/wireless/ath/main.c | 36 ++++++++++++++++++++++++++++
6 files changed, 75 insertions(+), 41 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath.h
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 253b95a..11ded15 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -5,9 +5,7 @@ menuconfig ATH_COMMON
---help---
This will enable the support for the Atheros wireless drivers.
ath5k, ath9k and ar9170 drivers share some common code, this option
- enables the common ath.ko module which currently shares just common
- regulatory EEPROM helpers but will likely be extended later to share
- more between modules.
+ enables the common ath.ko module which shares common helpers.
For more information and documentation on this module you can visit:
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
new file mode 100644
index 0000000..e284cd3
--- /dev/null
+++ b/drivers/net/wireless/ath/ath.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_H
+#define ATH_H
+
+#include <linux/skbuff.h>
+
+struct ath_common {
+ u16 cachelsz;
+};
+
+struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+ u32 len,
+ gfp_t gfp_mask);
+
+#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7a5a157..2fd663c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -25,6 +25,7 @@
#include "hw.h"
#include "rc.h"
#include "debug.h"
+#include "../ath.h"
struct ath_node;
@@ -532,6 +533,8 @@ struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
+ struct ath_common common;
+
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
struct ath_wiphy *pri_wiphy;
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
@@ -564,7 +567,6 @@ struct ath_softc {
u32 sc_flags; /* SC_OP_* */
u16 curtxpow;
u16 curaid;
- u16 cachelsz;
u8 nbcnvifs;
u16 nvifs;
u8 tx_chainmask;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index efe2e85..b29d0ff 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1327,7 +1327,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
*/
ath_read_cachesize(sc, &csz);
/* XXX assert csz is non-zero */
- sc->cachelsz = csz << 2; /* convert to bytes */
+ sc->common.cachelsz = csz << 2; /* convert to bytes */
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
if (!ah) {
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 1a08c69..61dbdd2 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -100,38 +100,6 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
return (tsf & ~0x7fff) | rstamp;
}
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask)
-{
- struct sk_buff *skb;
- u32 off;
-
- /*
- * Cache-line-align. This is important (for the
- * 5210 at least) as not doing so causes bogus data
- * in rx'd frames.
- */
-
- /* Note: the kernel can allocate a value greater than
- * what we ask it to give us. We really only need 4 KB as that
- * is this hardware supports and in fact we need at least 3849
- * as that is the MAX AMSDU size this hardware supports.
- * Unfortunately this means we may get 8 KB here from the
- * kernel... and that is actually what is observed on some
- * systems :( */
- skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask);
- if (skb != NULL) {
- off = ((unsigned long) skb->data) % sc->cachelsz;
- if (off != 0)
- skb_reserve(skb, sc->cachelsz - off);
- } else {
- DPRINTF(sc, ATH_DBG_FATAL,
- "skbuff alloc of size %u failed\n", len);
- return NULL;
- }
-
- return skb;
-}
-
/*
* For Decrypt or Demic errors, we only mark packet status here and always push
* up the frame up to let mac80211 handle the actual error case, be it no
@@ -336,10 +304,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
spin_lock_init(&sc->rx.rxbuflock);
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(sc->cachelsz, (u16)64));
+ min(sc->common.cachelsz, (u16)64));
DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- sc->cachelsz, sc->rx.bufsize);
+ sc->common.cachelsz, sc->rx.bufsize);
/* Initialize rx descriptors */
@@ -352,7 +320,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
+ skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@@ -777,7 +745,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC);
+ requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
index 9949b11..487193f 100644
--- a/drivers/net/wireless/ath/main.c
+++ b/drivers/net/wireless/ath/main.c
@@ -17,6 +17,42 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include "ath.h"
+
MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
+
+struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+ u32 len,
+ gfp_t gfp_mask)
+{
+ struct sk_buff *skb;
+ u32 off;
+
+ /*
+ * Cache-line-align. This is important (for the
+ * 5210 at least) as not doing so causes bogus data
+ * in rx'd frames.
+ */
+
+ /* Note: the kernel can allocate a value greater than
+ * what we ask it to give us. We really only need 4 KB as that
+ * is this hardware supports and in fact we need at least 3849
+ * as that is the MAX AMSDU size this hardware supports.
+ * Unfortunately this means we may get 8 KB here from the
+ * kernel... and that is actually what is observed on some
+ * systems :( */
+ skb = __dev_alloc_skb(len + common->cachelsz - 1, gfp_mask);
+ if (skb != NULL) {
+ off = ((unsigned long) skb->data) % common->cachelsz;
+ if (off != 0)
+ skb_reserve(skb, common->cachelsz - off);
+ } else {
+ printk(KERN_ERR "skbuff alloc of size %u failed\n", len);
+ return NULL;
+ }
+
+ return skb;
+}
+EXPORT_SYMBOL(ath_rxbuf_alloc);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 0/3] ath: advance ath.ko with one more helper
From: Luis R. Rodriguez @ 2009-08-12 16:56 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, ath9k-devel, ath5k-devel, Luis R. Rodriguez
This adds a common structure where we can start stuffing shared items
and introduces a helper for both ath5k and ath9k's use.
Luis R. Rodriguez (3):
ath: add common ath_rxbuf_alloc() and make ath9k use it
ath5k: use common ath.ko ath_rxbuf_alloc()
ath5k: use bit shift operators for cache line size
drivers/net/wireless/ath/Kconfig | 4 +--
drivers/net/wireless/ath/ath.h | 30 ++++++++++++++++++++++++
drivers/net/wireless/ath/ath5k/base.c | 23 ++++++------------
drivers/net/wireless/ath/ath5k/base.h | 3 +-
drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-
drivers/net/wireless/ath/ath9k/main.c | 2 +-
drivers/net/wireless/ath/ath9k/recv.c | 40 +++----------------------------
drivers/net/wireless/ath/main.c | 36 ++++++++++++++++++++++++++++
8 files changed, 85 insertions(+), 57 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath.h
^ permalink raw reply
* Re: ath5k warning on bitrate
From: Bob Copeland @ 2009-08-12 16:51 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linux-wireless, Nick Kossifidis
In-Reply-To: <43e72e890908120945l14f6590ev38f7083a1b1dae8@mail.gmail.com>
On Wed, Aug 12, 2009 at 12:45 PM, Luis R. Rodriguez<mcgrof@gmail.com> wrote:
> I have some patches on top of this for ath5k but I doubt they were the
> culprit. The warning comes from the second check:
> rix = sc->rate_idx[sc->curband->band][hw_rix];
> if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix))
> rix = 0;
Just another case of sc->curband being wrong when processing this.
> [ 402.717626] ath5k phy0: noise floor calibration timeout (2462MHz)
Because of a scan. Did we break the thing that flushed rx processing
on channel changes?
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* ath5k warning on bitrate
From: Luis R. Rodriguez @ 2009-08-12 16:45 UTC (permalink / raw)
To: linux-wireless; +Cc: Bob Copeland, Nick Kossifidis
I have some patches on top of this for ath5k but I doubt they were the
culprit. The warning comes from the second check:
static inline int
ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
{
int rix;
/* return base rate on errors */
if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES,
"hw_rix out of bounds: %x\n", hw_rix))
return 0;
rix = sc->rate_idx[sc->curband->band][hw_rix];
if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix))
rix = 0;
return rix;
}
[ 402.717626] ath5k phy0: noise floor calibration timeout (2462MHz)
[ 1443.232473] ------------[ cut here ]------------
[ 1443.232473] WARNING: at drivers/net/wireless/ath/ath5k/base.c:1140
ath5k_tasklet_rx+0x562/0x670 [ath5k]()
[ 1443.232473] Hardware name: 7660A14
[ 1443.232473] invalid hw_rix: 1b
[ 1443.232473] Modules linked in: aes_generic binfmt_misc ppdev bridge
stp bnep kvm_intel kvm lp parport snd_hda_codec_analog joydev arc4 ecb
snd_hda_intel snd_hda_codec snd_pcm_oss snd_mixer_oss snd_pcm ath5k
pcmcia snd_seq_dummy mac80211 ath snd_seq_oss snd_seq_midi_event
thinkpad_acpi yenta_socket psmouse cfg80211 rsrc_nonstatic pcspkr
snd_seq nvram serio_raw led_class pcmcia_core btusb snd_timer
snd_seq_device snd soundcore snd_page_alloc ohci1394 ieee1394 e1000e
fbcon tileblit font bitblit softcursor i915 drm i2c_algo_bit video
output intel_agp
[ 1443.232473] Pid: 0, comm: swapper Not tainted 2.6.31-rc5-wl #129
[ 1443.232473] Call Trace:
[ 1443.232473] <IRQ> [<ffffffff81057398>] warn_slowpath_common+0x78/0xb0
[ 1443.232473] [<ffffffff8105742c>] warn_slowpath_fmt+0x3c/0x40
[ 1443.232473] [<ffffffffa026be22>] ath5k_tasklet_rx+0x562/0x670 [ath5k]
[ 1443.232473] [<ffffffff810313b9>] ? default_spin_lock_flags+0x9/0x10
[ 1443.232473] [<ffffffff8105ca20>] tasklet_action+0xd0/0xe0
[ 1443.232473] [<ffffffff8105dd4d>] __do_softirq+0xbd/0x200
[ 1443.232473] [<ffffffff8101308c>] call_softirq+0x1c/0x30
[ 1443.232473] [<ffffffff81014805>] do_softirq+0x55/0x90
[ 1443.232473] [<ffffffff8105dab5>] irq_exit+0x85/0x90
[ 1443.232473] [<ffffffff81013f80>] do_IRQ+0x70/0xe0
[ 1443.232473] [<ffffffff810128d3>] ret_from_intr+0x0/0x11
[ 1443.232473] <EOI> [<ffffffff812c256a>] ? acpi_idle_enter_bm+0x28b/0x2bf
[ 1443.232473] [<ffffffff812c2563>] ? acpi_idle_enter_bm+0x284/0x2bf
[ 1443.232473] [<ffffffff813e088b>] ? cpuidle_idle_call+0x9b/0xf0
[ 1443.232473] [<ffffffff81010e12>] ? cpu_idle+0xb2/0x100
[ 1443.232473] [<ffffffff814e819b>] ? start_secondary+0x18e/0x193
[ 1443.232473] ---[ end trace 95c5af437c1ab783 ]---
^ permalink raw reply
* Re: [PATCH 2.6.30] iwl3945: fix rfkill switch
From: reinette chatre @ 2009-08-12 16:45 UTC (permalink / raw)
To: Stanislaw Gruszka
Cc: linux-wireless@vger.kernel.org, Zhu, Yi, John W. Linville,
stable@kernel.org
In-Reply-To: <20090812151235.GA3912@dhcp-lab-161.englab.brq.redhat.com>
Hi Stanislaw,
On Wed, 2009-08-12 at 08:12 -0700, Stanislaw Gruszka wrote:
> On Tue, Aug 11, 2009 at 11:08:33AM -0700, reinette chatre wrote:
>
> > STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> > driver HW on
> > STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> > rfkill SW on ( -> rfkill_epo() -> rfkill_toggle_radio() with force = 1)
> > STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> > rfkill SW off
> > STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> No, rfkill core will not call ->toggle_radio()
oh ... I see .... in rfkill_toggle_radio -EPERM is returned in this
case.
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> > driver HW off (called from iwl_bg_rf_kill())
> > STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> Would be:
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_UNBLOCKED
>
> Not work without the patch, with patch it works like that:
>
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> driver HW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> rfkill SW on
> rfkill call -> rfkill_epo() -> rfkill_toggle_radio(RFKILL_STATE_SOFT_BLOCKED)
> with force = 1 . Due to changes in iwl_rfkill_soft_rf_kill() we move
> state to RFKILL_STATE_SOFT_BLOCKED, so:
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
> rfkill SW off
> rfkill core call ->toggle_radio(RFKILL_STATE_UNBLOCKED)
> iwl_is_rfkill_hw(priv) is true but we disable STATUS_RF_KILL_SW
> anyway and return -EBUSY to not change rfkill core state, so:
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_SOFT_BLOCKED
> driver HW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
I see ... the state mismatch is a bit strange, but you talk about that
later ...
> > I understand that one hunk of your patch accomplishes the mapping of
> > "STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=1 <->
> > RFKILL_STATUS_SOFT_BLOCKED" - but I do not understand why it is needed. Could you please explain?
>
> I hope above explanation are clear now.
yes - thank you very much.
>
> > I also do not understand the need to modify rfkill's internal state.
>
> It's needed for Case1. Additional change of internal rfkill state, which
> I proposed in previous e-mail is against situation when we have:
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_SOFT_BLOCKED
> To make it:
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
ok - this makes sense now. In your previous email you also mentioned
that that delta patch was untested. Is it possible for you or anybody
else on that redhat bugzilla to give the new patch a try?
I think I now understand what is going on. Having worked through all the
possible scenarios makes me more comfortable about his patch considering
the awkward way in which it is forced to solve the problem. I am really
glad we do not need to do this moving forward.
Reinette
^ permalink raw reply
* Re: Staging: rt2870: new USB ID for Belkin N+ F5D8055
From: Gábor Stefanik @ 2009-08-12 16:43 UTC (permalink / raw)
To: Daniele Napolitano; +Cc: linux-wireless, gregkh, akpm, greg
In-Reply-To: <15d0b9b20908120920sa42235ft4ce0daed4e4f0130@mail.gmail.com>
On Wed, Aug 12, 2009 at 6:20 PM, Daniele Napolitano<dnax88@gmail.com> wrote:
> In attachment patch and its gpg sign.
>
> I've made this patch with drivers/staging branch found here:
> http://git.kernel.org/?p=linux/kernel/git/gregkh/staging-2.6.git
>
> Regards.
>
> --
> Daniele "DnaX" Napolitano
> https://launchpad.net/~dnax88
>
Please read http://linux.yyz.us/patch-format.html.
--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)
^ permalink raw reply
* Staging: rt2870: new USB ID for Belkin N+ F5D8055
From: Daniele Napolitano @ 2009-08-12 16:20 UTC (permalink / raw)
To: linux-wireless, gregkh, akpm, greg
[-- Attachment #1: Type: text/plain, Size: 236 bytes --]
In attachment patch and its gpg sign.
I've made this patch with drivers/staging branch found here:
http://git.kernel.org/?p=linux/kernel/git/gregkh/staging-2.6.git
Regards.
--
Daniele "DnaX" Napolitano
https://launchpad.net/~dnax88
[-- Attachment #2: rt2870-add-id-for-belkin-f5d8055.patch --]
[-- Type: text/x-diff, Size: 515 bytes --]
Signed-off-by: Daniele Napolitano <dnax88@gmail.com>
--- rt2870.h 2009-08-12 18:06:42.606925649 +0200
+++ rt2870_patched.h 2009-08-12 18:07:11.698931370 +0200
@@ -102,6 +102,7 @@
{USB_DEVICE(0x14B2,0x3C12)}, /* AL */ \
{USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \
{USB_DEVICE(0x050D,0x815C)}, /* Belkin */ \
+ {USB_DEVICE(0x050D,0x825a)}, /* Belkin */ \
{USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \
{USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \
{USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \
[-- Attachment #3: rt2870-add-id-for-belkin-f5d8055.patch.gpg --]
[-- Type: application/pgp-encrypted, Size: 395 bytes --]
^ permalink raw reply
* Re: Libertas: Association request to the driver failed
From: Dan Williams @ 2009-08-12 16:16 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Roel Kluin, Cyrill Gorcunov, Michael Buesch, libertas-dev,
linux-wireless, linux-kernel, John W. Linville, Daniel Mack
In-Reply-To: <4A8281AD.1010807@cam.ac.uk>
On Wed, 2009-08-12 at 08:47 +0000, Jonathan Cameron wrote:
> Hi All,
>
> After applying this patch I've been receiving 0x12 response from
> an access point (association failed: not all rates supported)
> to association requests.
>
> See below for queries on what is happening,
> > Several arrays were read before checking whether the index was within
> > bounds. ARRAY_SIZE() should be used to determine the size of arrays.
> >
> > rates->rates has an arraysize of 1, so calling get_common_rates()
> > with a rates_size of MAX_RATES (14) was causing reads out of bounds.
> >
> > tmp_size can increment at most to MAX_RATES * ARRAY_SIZE(lbs_bg_rates),
> > so that should be the number of elements of tmp[].
> >
> > Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
> > ---
> >
> >> | Is it a good idea to use dynamic stack arrays in the kernel?
> >> | What about kmalloc for dynamic allocations?
> >> |
> >> | --
> >> | Greetings, Michael.
> >>
> >> I saw one pattern in trace code (not sure if it's
> >> still there) but personally don't like dynamic
> >> stack arrays (though at moment the max value
> >> being passed into routine is known maybe just
> >> use MAX_RATES instead of (*rates_size)?). Hmm?
> >
> > Good point.
> >
> >> -- Cyrill
> >
> > Thanks,
> >
> > I think there was another problem in lbs_associate(),
> > the memcpy already affected rates->rates.
> >
> > Also in get_common_rates() I think we can safely move the
> > memset/memcpy, originally after label done, upwards.
> >
> > The patch below, if correct, is to be applied after the revert
> >
> > Roel
> >
> > diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
> > index b9b3741..ba0164a 100644
> > --- a/drivers/net/wireless/libertas/assoc.c
> > +++ b/drivers/net/wireless/libertas/assoc.c
> > @@ -1,6 +1,7 @@
> > /* Copyright (C) 2006, Red Hat, Inc. */
> >
> > #include <linux/types.h>
> > +#include <linux/kernel.h>
> > #include <linux/etherdevice.h>
> > #include <linux/ieee80211.h>
> > #include <linux/if_arp.h>
> > @@ -43,41 +44,41 @@ static int get_common_rates(struct lbs_private *priv,
> > u16 *rates_size)
> > {
> > u8 *card_rates = lbs_bg_rates;
> > - size_t num_card_rates = sizeof(lbs_bg_rates);
> > - int ret = 0, i, j;
> > - u8 tmp[30];
> > + int i, j;
> > + u8 tmp[MAX_RATES * ARRAY_SIZE(lbs_bg_rates)];
> > size_t tmp_size = 0;
> >
> > /* For each rate in card_rates that exists in rate1, copy to tmp */
> > - for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
> > - for (j = 0; rates[j] && (j < *rates_size); j++) {
> > + for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
> > + for (j = 0; j < *rates_size && rates[j]; j++) {
> > if (rates[j] == card_rates[i])
> > tmp[tmp_size++] = card_rates[i];
> > }
> > }
> >
> > lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
> > - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
> > + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates,
> > + ARRAY_SIZE(lbs_bg_rates));
> > lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
> > lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
> >
> > + memset(rates, 0, *rates_size);
> > + *rates_size = min_t(u16, tmp_size, *rates_size);
> > + memcpy(rates, tmp, *rates_size);
> > +
> > if (!priv->enablehwauto) {
> > for (i = 0; i < tmp_size; i++) {
> > if (tmp[i] == priv->cur_rate)
> > - goto done;
> > + break;
> > + }
> > + if (i == tmp_size) {
> > + lbs_pr_alert("Previously set fixed data rate %#x isn't "
> > + "compatible with the network.\n",
> > + priv->cur_rate);
> > + return -1;
> > }
> > - lbs_pr_alert("Previously set fixed data rate %#x isn't "
> > - "compatible with the network.\n", priv->cur_rate);
> > - ret = -1;
> > - goto done;
> > }
> > - ret = 0;
> > -
> > -done:
> > - memset(rates, 0, *rates_size);
> > - *rates_size = min_t(int, tmp_size, *rates_size);
> > - memcpy(rates, tmp, *rates_size);
> > - return ret;
> > + return 0;
> > }
> >
> >
> > @@ -321,8 +322,8 @@ static int lbs_associate(struct lbs_private *priv,
> >
> > rates = (struct mrvl_ie_rates_param_set *) pos;
> > rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
> > - memcpy(&rates->rates, &bss->rates, MAX_RATES);
> > - tmplen = MAX_RATES;
> > + tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
> Isn't this always going to be 1? Switching back to original version
> allows association to work for me.
>
> As is, it only allows one rate to be tested as ARRAY_SIZE(rates->rates)
> is always 1 as it stands.
No, it was basically supposed to be either the # of rates in rates, or
MAX_RATES (or something like that). Basically, it should *never* be 1,
it should be either the # of 802.11b rates (which is like 5) or the # of
802.11g rates (which is like 12 or 13 or something). But never 1.
Dan
> If this is the desired behaviour please explain why?
> I'll admit I'm not really sure what should be happening, I've merely
> been bisecting looking for what was causing a regression for me.
>
> > + memcpy(&rates->rates, &bss->rates, tmplen);
> > if (get_common_rates(priv, rates->rates, &tmplen)) {
> > ret = -1;
> > goto done;
> > @@ -598,7 +599,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
> >
> > /* Copy Data rates from the rates recorded in scan response */
> > memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
> > - ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
> > + ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
> > memcpy(cmd.bss.rates, bss->rates, ratesize);
> > if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
> > lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
> >
> > _______________________________________________
> > libertas-dev mailing list
> > libertas-dev@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/libertas-dev
> >
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Libertas: Association request to the driver failed
From: Dan Williams @ 2009-08-12 16:15 UTC (permalink / raw)
To: John W. Linville
Cc: Roel Kluin, Daniel Mack, libertas-dev, linux-wireless,
linux-kernel
In-Reply-To: <20090811182426.GE2634@tuxdriver.com>
On Tue, 2009-08-11 at 14:24 -0400, John W. Linville wrote:
> Comments from the libertas crowd? This seems a bit long for this
> part of the cycle.
>
> Should we just revert the original patch, then reapply it with this
> one for 2.6.32?
I'd feel more comfortable with that. Roel did find a real problem, but
we need to make sure the fix doesn't break stuff since it appears the
rate code is more complicated than we thought.
Dan
> John
>
> On Tue, Aug 11, 2009 at 09:02:14AM +0200, Roel Kluin wrote:
> > The size of the tmp buffer was too small, causing a regression
> >
> > rates->rates has an arraysize of 1, so a memcpy with
> > MAX_RATES (14) was already causing reads out of bounds.
> >
> > In get_common_rates() the memset/memcpy can be moved upwards.
> >
> > Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
> > Tested-by: Daniel Mack <daniel@caiaq.de>
> > ---
> > > Delta patch, please...
> >
> > Here,
> >
> > diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
> > index d699737..ba0164a 100644
> > --- a/drivers/net/wireless/libertas/assoc.c
> > +++ b/drivers/net/wireless/libertas/assoc.c
> > @@ -44,8 +44,8 @@ static int get_common_rates(struct lbs_private *priv,
> > u16 *rates_size)
> > {
> > u8 *card_rates = lbs_bg_rates;
> > - int ret = 0, i, j;
> > - u8 tmp[(ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1)];
> > + int i, j;
> > + u8 tmp[MAX_RATES * ARRAY_SIZE(lbs_bg_rates)];
> > size_t tmp_size = 0;
> >
> > /* For each rate in card_rates that exists in rate1, copy to tmp */
> > @@ -62,20 +62,23 @@ static int get_common_rates(struct lbs_private *priv,
> > lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
> > lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
> >
> > + memset(rates, 0, *rates_size);
> > + *rates_size = min_t(u16, tmp_size, *rates_size);
> > + memcpy(rates, tmp, *rates_size);
> > +
> > if (!priv->enablehwauto) {
> > for (i = 0; i < tmp_size; i++) {
> > if (tmp[i] == priv->cur_rate)
> > - goto done;
> > + break;
> > + }
> > + if (i == tmp_size) {
> > + lbs_pr_alert("Previously set fixed data rate %#x isn't "
> > + "compatible with the network.\n",
> > + priv->cur_rate);
> > + return -1;
> > }
> > - lbs_pr_alert("Previously set fixed data rate %#x isn't "
> > - "compatible with the network.\n", priv->cur_rate);
> > - ret = -1;
> > }
> > -done:
> > - memset(rates, 0, *rates_size);
> > - *rates_size = min_t(int, tmp_size, *rates_size);
> > - memcpy(rates, tmp, *rates_size);
> > - return ret;
> > + return 0;
> > }
> >
> >
> > @@ -319,8 +322,8 @@ static int lbs_associate(struct lbs_private *priv,
> >
> > rates = (struct mrvl_ie_rates_param_set *) pos;
> > rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
> > - memcpy(&rates->rates, &bss->rates, MAX_RATES);
> > tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
> > + memcpy(&rates->rates, &bss->rates, tmplen);
> > if (get_common_rates(priv, rates->rates, &tmplen)) {
> > ret = -1;
> > goto done;
> >
>
^ permalink raw reply
* Re: [PATCH] iwl3945: fix compilation error in iwl3945_pass_packet_to_mac80211()
From: reinette chatre @ 2009-08-12 15:37 UTC (permalink / raw)
To: Kalle Valo; +Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org
In-Reply-To: <20090812110727.4963.99515.stgit@tikku>
On Wed, 2009-08-12 at 04:07 -0700, Kalle Valo wrote:
> Commit "iwlwifi: Traffic type and counter for debugFs" broke iwl3945 in
> a case when CONFIG_IWLWIFI_LEDS is disabled:
>
> drivers/net/wireless/iwlwifi/iwl-3945.c:580: error: 'hdr' undeclared (first use in this function)
>
> Fix it by removing the ifdef check for hdr variable.
>
> Signed-off-by: Kalle Valo <kalle.valo@iki.fi>
> ---
>
> drivers/net/wireless/iwlwifi/iwl-3945.c | 2 --
> 1 files changed, 0 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
> index ae7f163..ba5ef83 100644
> --- a/drivers/net/wireless/iwlwifi/iwl-3945.c
> +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
> @@ -544,9 +544,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
> struct ieee80211_rx_status *stats)
> {
> struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
> -#ifdef CONFIG_IWLWIFI_LEDS
> struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
> -#endif
> struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
> struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
> short len = le16_to_cpu(rx_hdr->len);
>
We have an identical patch pending. I assumed most people compile with
led support and thus did not rush to get it in. Now that it is a problem
for more people I think this one should go in.
Acked-by: Reinette Chatre <reinette.chatre@intel.com>
Thank you
Reinette
^ permalink raw reply
* Re: [PATCH 2.6.30] iwl3945: fix rfkill switch
From: Stanislaw Gruszka @ 2009-08-12 15:12 UTC (permalink / raw)
To: reinette chatre
Cc: linux-wireless@vger.kernel.org, Zhu, Yi, John W. Linville,
stable@kernel.org
In-Reply-To: <1250014113.30019.5799.camel@rc-desk>
On Tue, Aug 11, 2009 at 11:08:33AM -0700, reinette chatre wrote:
> Hi Stanislaw,
>
> Thank you for your patience ...
Hello, I understand your concerns, patch is not so straightforward and
hard to understand, if you don't have system where you can reproduce.
> On Tue, 2009-08-11 at 07:09 -0700, Stanislaw Gruszka wrote:
> > On Mon, Aug 10, 2009 at 09:44:52AM -0700, reinette chatre wrote:
> > > Yes. I assume that what happens here is that rfkill notifies user that
> > > state changes to RFKILL_STATE_UNBLOCKED. In your new patch the driver
> > > will now clear STATUS_RF_KILL_SW, with STATUS_RF_KILL_HW still being
> > > set. So, in this run, after iwl_rfkill_soft_rf_kill is called there will
> > > be a state mismatch with rfkill thinking the system is unblocked while
> > > the driver has it as hard blocked. This is not right.
> >
> > In such case we return -EBUSY from iwl_rfkill_soft_rf_kill() - rfkill
> > state not change.
>
> oh - right - sorry
>
> > I made a comment it will be HARD_BLOCKED, this
> > is not true anymore, it can be also in state SOFT_BLOCKED .
>
> How so? Isn't the idea behind toggle_radio that the SOFT_BLOCKED state
> changes? In this case when we get a new state of UNBLOCKED then I do not
> understand how SOFT_BLOCKED can be true also.
Hugh, right I was completely wrong here.
> > However
> > comment was true with previous version of the patch for 2.6.29, where
> > there was no HARD -> SOFT downgrade and that part was called only when
> > rfkill state was HARD_BLOCKED.
> >
> > > Can this be fixed by adding a iwl_rfkill_set_hw_state in this run?
> >
> > We can not call iwl_rfkill_set_hw_state in iwl_rfkill_soft_rt_kill
> > as rfkill->muttex is taken. We eventually can force state in the same ugly
> > way as is done for case RFKILL_STATE_SOFT_BLOCKED and I think, this is good
> > idea :) , below not tested delta patch:
> >
>
> This just seems to mess with the rfkill internals even more. Can this
> not be avoided?
Other solution eventually would be ignore rfkill core request to SW disable
radio when we have already STATUS_RF_KILL_HW=1, but I think it is very bad
idea and probably broke thinks.
We currently call rfkill_force_state() which is changing internal state
of rfkill core, however it is done through defined api. Uh, patch is
not ideal, but I do not have anything better.
> > > >From what I can tell this patch introduced a disagreement of rfkill
> > > state between driver and rfkill system.
> >
> > In driver we have no states, but separate bits for each killswitch. Situation
> > gets better after rfkill rewrite where also rfkill core become to have separate
> > bits, but with 2.6.30 we have no such luck.
> >
> > Currently we have "states" like below:
> >
> > STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=1 <-> RFKILL_STATUS_HARD_BLOCKED
> > STATUS_RF_KILL_HW=0 STATUS_RF_KILL_SW=1 <-> RFKILL_STATUS_SOFT_BLOCKED
> > STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=0 <-> RFKILL_STATUS_HARD_BLOCKED
> > STATUS_RF_KILL_HW=0 STATUS_RF_KILL_SW=0 <-> RFKILL_STATUS_UNBLOCKED
> >
> > Patch is intended to work like that:
> >
> > STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=1 <-> RFKILL_STATUS_SOFT_BLOCKED
> > STATUS_RF_KILL_HW=0 STATUS_RF_KILL_SW=1 <-> RFKILL_STATUS_SOFT_BLOCKED
> > STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=0 <-> RFKILL_STATUS_HARD_BLOCKED
> > STATUS_RF_KILL_HW=0 STATUS_RF_KILL_SW=0 <-> RFKILL_STATUS_UNBLOCKED
>
> I can see that this is what the last hunk of the patch accomplishes -
> but I do not see why it is needed.
>
> >
> > STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> >
> > driver HW on
> >
> > STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> >
> > rfkill SW on ( -> rfkill_epo() -> rfkill_toggle_radio() with force = 1)
> >
> > STATUS_RF_KILL_HW=1, STATUS_RF_KILL_SW=1, RFKILL_STATE_HARD_BLOCKED
> >
> > rfkill SW off (HARD_BLOCKED not clearing STATUS_RF_KILL_SW)
> >
> > STATUS_RF_KILL_HW=1, STATUS_RF_KILL_SW=1, RFKILL_STATE_HARD_BLOCKED
> >
> > driver HW off (called from iwl_bg_rf_kill())
> >
> > STATUS_RF_KILL_HW=0, STATUS_RF_KILL_SW=1, RFKILL_STATE_SOFT_BLOCKED
> >
> > rfkill core no longer wants to turn radio on
>
> >From what I understand what you are describing above should be addressed
> by this hunk of your patch:
>
> case RFKILL_STATE_UNBLOCKED:
> if (iwl_is_rfkill_hw(priv)) {
> err = -EBUSY;
> - goto out_unlock;
> + /* pass error to rfkill core to make it state HARD
> + * BLOCKED and disable software kill switch */
> }
>
> This should make these new transitions possible:
>
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> driver HW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> rfkill SW on ( -> rfkill_epo() -> rfkill_toggle_radio() with force = 1)
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> rfkill SW off
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
No, rfkill core will not call ->toggle_radio()
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> driver HW off (called from iwl_bg_rf_kill())
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
Would be:
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_UNBLOCKED
Not work without the patch, with patch it works like that:
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
driver HW on
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
rfkill SW on
rfkill call -> rfkill_epo() -> rfkill_toggle_radio(RFKILL_STATE_SOFT_BLOCKED)
with force = 1 . Due to changes in iwl_rfkill_soft_rf_kill() we move
state to RFKILL_STATE_SOFT_BLOCKED, so:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
rfkill SW off
rfkill core call ->toggle_radio(RFKILL_STATE_UNBLOCKED)
iwl_is_rfkill_hw(priv) is true but we disable STATUS_RF_KILL_SW
anyway and return -EBUSY to not change rfkill core state, so:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_SOFT_BLOCKED
driver HW off
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> Looking further I tried to see how other combinations would be treated. Here is how I see the potential scenarios:
>
> Case1 (considered above):
> driver HW on -> rfkill SW on -> rfkill SW off -> driver HW off
> Case2:
> driver HW on -> rfkill SW on -> driver HW off -> rfkill SW off
> Case3:
> rfkill SW on -> driver HW on -> rfkill SW off -> driver HW off
> Case4:
> rfkill SW on -> driver HW on -> driver HW off -> rfkill SW off
>
> Looking at the rest of the cases I do not see the problem addressed by the other hunks.
>
> I see:
>
> Case 2:
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> driver HW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> rfkill SW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> driver HW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
> rfkill SW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
Yes, works without the patch.
> Case3:
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> rfkill SW on
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
> driver HW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> rfkill SW off
No, rfkill will not call ->toggle_radio()
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
> driver HW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
Not work without the patch, with patch it works like that:
Case3:
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
rfkill SW on
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
driver HW on
Here due to changes in iwl_rfkill_set_hw_state() rfkill core stay in
RFKILL_STATE_SOFT_BLOCKED so:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
rfkill SW off
rfkill core call ->toggle_radio(RFKILL_STATE_UNBLOCKED)
iwl_is_rfkill_hw(priv) is true but we disable STATUS_RF_KILL_SW
anyway and return -EBUSY to not change rfkill core state, so:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_SOFT_BLOCKED
driver HW off
STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> Case4:
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
> rfkill SW on
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
> driver HW on
> STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 1, RFKILL_STATE_HARD_BLOCKED
> driver HW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 1, RFKILL_STATE_SOFT_BLOCKED
> rfkill SW off
> STATUS_RF_KILL_HW = 0, STATUS_RF_KILL_SW = 0, RFKILL_STATE_UNBLOCKED
>
Yes, work without the patch.
> I understand that one hunk of your patch accomplishes the mapping of
> "STATUS_RF_KILL_HW=1 STATUS_RF_KILL_SW=1 <->
> RFKILL_STATUS_SOFT_BLOCKED" - but I do not understand why it is needed. Could you please explain?
I hope above explanation are clear now.
> I also do not understand the need to modify rfkill's internal state.
It's needed for Case1. Additional change of internal rfkill state, which
I proposed in previous e-mail is against situation when we have:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_SOFT_BLOCKED
To make it:
STATUS_RF_KILL_HW = 1, STATUS_RF_KILL_SW = 0, RFKILL_STATE_HARD_BLOCKED
Regards
Stanislaw
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox